soroban_fixed_point_math/
u64.rs

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