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