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