1use crate::fixed_point::FixedPoint;
2
3impl FixedPoint for i128 {
4 fn fixed_mul_floor(self, y: i128, denominator: i128) -> Option<i128> {
5 mul_div_floor(self, y, denominator)
6 }
7
8 fn fixed_mul_ceil(self, y: i128, denominator: i128) -> Option<i128> {
9 mul_div_ceil(self, y, denominator)
10 }
11
12 fn fixed_div_floor(self, y: i128, denominator: i128) -> Option<i128> {
13 mul_div_floor(self, denominator, y)
14 }
15
16 fn fixed_div_ceil(self, y: i128, denominator: i128) -> Option<i128> {
17 mul_div_ceil(self, denominator, y)
18 }
19}
20
21fn mul_div_floor(x: i128, y: i128, z: i128) -> Option<i128> {
26 let r = x.checked_mul(y)?;
27 if r < 0 || (r > 0 && z < 0) {
28 let remainder = r.checked_rem_euclid(z)?;
30 (r / z).checked_sub(if remainder > 0 { 1 } else { 0 })
31 } else {
32 r.checked_div(z)
34 }
35}
36
37fn mul_div_ceil(x: i128, y: i128, z: i128) -> Option<i128> {
39 let r = x.checked_mul(y)?;
40 if r <= 0 || (r > 0 && z < 0) {
41 r.checked_div(z)
43 } else {
44 let remainder = r.checked_rem_euclid(z)?;
46 (r / z).checked_add(if remainder > 0 { 1 } else { 0 })
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
57 fn test_fixed_mul_floor_rounds_down() {
58 let x: i128 = 1_5391283;
59 let y: i128 = 314_1592653;
60 let denominator: i128 = 1_0000001;
61
62 let result = x.fixed_mul_floor(y, denominator).unwrap();
63
64 assert_eq!(result, 483_5313675)
65 }
66
67 #[test]
68 fn test_fixed_mul_floor_negative_rounds_down() {
69 let x: i128 = -1_5391283;
70 let y: i128 = 314_1592653;
71 let denominator: i128 = 1_0000001;
72
73 let result = x.fixed_mul_floor(y, denominator).unwrap();
74
75 assert_eq!(result, -483_5313676)
76 }
77
78 #[test]
79 fn test_fixed_mul_floor_large_number() {
80 let x: i128 = 170_141_183_460_469_231_731;
81 let y: i128 = 1_000_000_000_000_000_000;
82 let denominator: i128 = 1_000_000_000_000_000_000;
83
84 let result = x.fixed_mul_floor(y, denominator).unwrap();
85
86 assert_eq!(result, 170_141_183_460_469_231_731)
87 }
88
89 #[test]
90 fn test_fixed_mul_floor_phantom_overflow() {
91 let x: i128 = 170_141_183_460_469_231_731;
92 let y: i128 = 1_000_000_000_000_000_001;
93 let denominator: i128 = 1_000_000_000_000_000_000;
94
95 let result = x.fixed_mul_floor(y, denominator);
96
97 assert_eq!(None, result);
98 }
99
100 #[test]
103 fn test_fixed_mul_ceil_rounds_up() {
104 let x: i128 = 1_5391283;
105 let y: i128 = 314_1592653;
106 let denominator: i128 = 1_0000001;
107
108 let result = x.fixed_mul_ceil(y, denominator).unwrap();
109
110 assert_eq!(result, 483_5313676)
111 }
112
113 #[test]
114 fn test_fixed_mul_ceil_negative_rounds_up() {
115 let x: i128 = -1_5391283;
116 let y: i128 = 314_1592653;
117 let denominator: i128 = 1_0000001;
118
119 let result = x.fixed_mul_ceil(y, denominator).unwrap();
120
121 assert_eq!(result, -483_5313675)
122 }
123
124 #[test]
125 fn test_fixed_mul_ceil_large_number() {
126 let x: i128 = 170_141_183_460_469_231_731;
127 let y: i128 = 1_000_000_000_000_000_000;
128 let denominator: i128 = 1_000_000_000_000_000_000;
129
130 let result = x.fixed_mul_ceil(y, denominator).unwrap();
131
132 assert_eq!(result, 170_141_183_460_469_231_731)
133 }
134
135 #[test]
136 fn test_fixed_mul_ceil_phantom_overflow() {
137 let x: i128 = 170_141_183_460_469_231_731;
138 let y: i128 = 1_000_000_000_000_000_001;
139 let denominator: i128 = 1_000_000_000_000_000_000;
140
141 let result = x.fixed_mul_ceil(y, denominator);
142
143 assert_eq!(None, result);
144 }
145
146 #[test]
149 fn test_fixed_div_floor_rounds_down() {
150 let x: i128 = 314_1592653;
151 let y: i128 = 1_5391280;
152 let denominator: i128 = 1_0000000;
153
154 let result = x.fixed_div_floor(y, denominator).unwrap();
155
156 assert_eq!(result, 204_1150997)
157 }
158
159 #[test]
160 fn test_fixed_div_floor_negative_rounds_down() {
161 let x: i128 = 314_1592653;
162 let y: i128 = -1_5391280;
163 let denominator: i128 = 1_0000000;
164
165 let result = x.fixed_div_floor(y, denominator).unwrap();
166
167 assert_eq!(result, -204_1150998)
168 }
169
170 #[test]
171 fn test_fixed_div_floor_large_number() {
172 let x: i128 = 170_141_183_460_469_231_731;
173 let y: i128 = 1_000_000_000_000_000_000;
174 let denominator: i128 = 1_000_000_000_000_000_000;
175
176 let result = x.fixed_div_floor(y, denominator).unwrap();
177
178 assert_eq!(result, 170_141_183_460_469_231_731)
179 }
180
181 #[test]
182 fn test_fixed_div_floor_phantom_overflow() {
183 let x: i128 = 170_141_183_460_469_231_732;
184 let y: i128 = 1_000_000_000_000_000_000;
185 let denominator: i128 = 1_000_000_000_000_000_000;
186
187 let result = x.fixed_div_floor(y, denominator);
188
189 assert_eq!(None, result);
190 }
191
192 #[test]
195 fn test_fixed_div_ceil_rounds_down() {
196 let x: i128 = 314_1592653;
197 let y: i128 = 1_5391280;
198 let denominator: i128 = 1_0000000;
199
200 let result = x.fixed_div_ceil(y, denominator).unwrap();
201
202 assert_eq!(result, 204_1150998)
203 }
204
205 #[test]
206 fn test_fixed_div_ceil_negative_rounds_down() {
207 let x: i128 = 314_1592653;
208 let y: i128 = -1_5391280;
209 let denominator: i128 = 1_0000000;
210
211 let result = x.fixed_div_ceil(y, denominator).unwrap();
212
213 assert_eq!(result, -204_1150997)
214 }
215
216 #[test]
217 fn test_fixed_div_ceil_large_number() {
218 let x: i128 = 170_141_183_460_469_231_731;
219 let y: i128 = 1_000_000_000_000_000_000;
220 let denominator: i128 = 1_000_000_000_000_000_000;
221
222 let result = x.fixed_div_ceil(y, denominator).unwrap();
223
224 assert_eq!(result, 170_141_183_460_469_231_731)
225 }
226
227 #[test]
228 fn test_fixed_div_ceil_phantom_overflow() {
229 let x: i128 = 170_141_183_460_469_231_732;
230 let y: i128 = 1_000_000_000_000_000_000;
231 let denominator: i128 = 1_000_000_000_000_000_000;
232
233 let result = x.fixed_div_ceil(y, denominator);
234
235 assert_eq!(None, result);
236 }
237}