soroban_fixed_point_math/
i256.rs1use soroban_sdk::{Env, I256};
2
3use crate::soroban_fixed_point::SorobanFixedPoint;
4
5impl SorobanFixedPoint for I256 {
6 fn fixed_mul_floor(&self, env: &Env, y: &I256, denominator: &I256) -> I256 {
7 mul_div_floor(env, &self, y, denominator)
8 }
9
10 fn fixed_mul_ceil(&self, env: &Env, y: &I256, denominator: &I256) -> I256 {
11 mul_div_ceil(env, &self, y, denominator)
12 }
13
14 fn fixed_div_floor(&self, env: &Env, y: &I256, denominator: &I256) -> I256 {
15 mul_div_floor(env, &self, denominator, y)
16 }
17
18 fn fixed_div_ceil(&self, env: &Env, y: &I256, denominator: &I256) -> I256 {
19 mul_div_ceil(env, &self, denominator, y)
20 }
21}
22
23pub(crate) fn mul_div_floor(env: &Env, x: &I256, y: &I256, z: &I256) -> I256 {
25 let zero = I256::from_i32(env, 0);
26 let r = x.mul(&y);
27 if r < zero || (r > zero && z.clone() < zero) {
28 let remainder = r.rem_euclid(&z);
30 let one = I256::from_i32(env, 1);
31 r.div(&z).sub(if remainder > zero { &one } else { &zero })
32 } else {
33 r.div(&z)
35 }
36}
37
38pub(crate) fn mul_div_ceil(env: &Env, x: &I256, y: &I256, z: &I256) -> I256 {
40 let zero = I256::from_i32(env, 0);
41 let r = x.mul(&y);
42 if r <= zero || (r > zero && z.clone() < zero) {
43 r.div(&z)
45 } else {
46 let remainder = r.rem_euclid(&z);
48 let one = I256::from_i32(env, 1);
49 r.div(&z).add(if remainder > zero { &one } else { &zero })
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
60 fn test_fixed_mul_floor_rounds_down() {
61 let env = Env::default();
62 let x: I256 = I256::from_i128(&env, 1_5391283);
63 let y: I256 = I256::from_i128(&env, 314_1592653);
64 let denominator: I256 = I256::from_i128(&env, 1_0000001);
65
66 let result = x.fixed_mul_floor(&env, &y, &denominator);
67
68 assert_eq!(result, I256::from_i128(&env, 483_5313675));
69 }
70
71 #[test]
72 fn test_fixed_mul_floor_negative_rounds_down() {
73 let env = Env::default();
74 let x: I256 = I256::from_i128(&env, -1_5391283);
75 let y: I256 = I256::from_i128(&env, 314_1592653);
76 let denominator: I256 = I256::from_i128(&env, 1_0000001);
77
78 let result = x.fixed_mul_floor(&env, &y, &denominator);
79
80 assert_eq!(result, I256::from_i128(&env, -483_5313676));
81 }
82
83 #[test]
84 fn test_fixed_mul_floor_large_number() {
85 let env = Env::default();
86 let x: I256 = I256::from_i128(&env, i128::MAX);
87 let y: I256 = I256::from_i128(&env, 10i128.pow(38));
88 let denominator: I256 = I256::from_i128(&env, 10i128.pow(18));
89
90 let result = x.clone().fixed_mul_floor(&env, &y, &denominator);
91
92 let expected_result = x.mul(&I256::from_i128(&env, 10i128.pow(20)));
93 assert_eq!(result, expected_result);
94 }
95
96 #[test]
97 #[should_panic(expected = "attempt to multiply with overflow")]
98 fn test_fixed_mul_floor_phantom_overflow() {
99 let env = Env::default();
100 let x: I256 = I256::from_i128(&env, i128::MAX);
101 let y: I256 = I256::from_i128(&env, 10i128.pow(39));
103 let denominator: I256 = I256::from_i128(&env, 10i128.pow(18));
104
105 x.fixed_mul_floor(&env, &y, &denominator);
106 }
107
108 #[test]
111 fn test_fixed_mul_ceil_rounds_up() {
112 let env = Env::default();
113 let x: I256 = I256::from_i128(&env, 1_5391283);
114 let y: I256 = I256::from_i128(&env, 314_1592653);
115 let denominator: I256 = I256::from_i128(&env, 1_0000001);
116
117 let result = x.fixed_mul_ceil(&env, &y, &denominator);
118
119 assert_eq!(result, I256::from_i128(&env, 483_5313676));
120 }
121
122 #[test]
123 fn test_fixed_mul_ceil_negative_rounds_up() {
124 let env = Env::default();
125 let x: I256 = I256::from_i128(&env, -1_5391283);
126 let y: I256 = I256::from_i128(&env, 314_1592653);
127 let denominator: I256 = I256::from_i128(&env, 1_0000001);
128
129 let result = x.fixed_mul_ceil(&env, &y, &denominator);
130
131 assert_eq!(result, I256::from_i128(&env, -483_5313675));
132 }
133
134 #[test]
135 fn test_fixed_mul_ceil_large_number() {
136 let env = Env::default();
137 let x: I256 = I256::from_i128(&env, i128::MAX);
138 let y: I256 = I256::from_i128(&env, 10i128.pow(38));
139 let denominator: I256 = I256::from_i128(&env, 10i128.pow(18));
140
141 let result = x.clone().fixed_mul_ceil(&env, &y, &denominator);
142
143 let expected_result = x.mul(&I256::from_i128(&env, 10i128.pow(20)));
144 assert_eq!(result, expected_result);
145 }
146
147 #[test]
148 #[should_panic(expected = "attempt to multiply with overflow")]
149 fn test_fixed_mul_ceil_phantom_overflow() {
150 let env = Env::default();
151 let x: I256 = I256::from_i128(&env, i128::MAX);
152 let y: I256 = I256::from_i128(&env, 10i128.pow(39));
154 let denominator: I256 = I256::from_i128(&env, 10i128.pow(18));
155
156 x.fixed_mul_ceil(&env, &y, &denominator);
157 }
158
159 #[test]
162 fn test_fixed_div_floor_rounds_down() {
163 let env = Env::default();
164 let x: I256 = I256::from_i128(&env, 314_1592653);
165 let y: I256 = I256::from_i128(&env, 1_5391280);
166 let denominator: I256 = I256::from_i128(&env, 1_0000000);
167
168 let result = x.fixed_div_floor(&env, &y, &denominator);
169
170 assert_eq!(result, I256::from_i128(&env, 204_1150997));
171 }
172
173 #[test]
174 fn test_fixed_div_floor_negative_rounds_down() {
175 let env = Env::default();
176 let x: I256 = I256::from_i128(&env, 314_1592653);
177 let y: I256 = I256::from_i128(&env, -1_5391280);
178 let denominator: I256 = I256::from_i128(&env, 1_0000000);
179
180 let result = x.fixed_div_floor(&env, &y, &denominator);
181
182 assert_eq!(result, I256::from_i128(&env, -204_1150998));
183 }
184
185 #[test]
186 fn test_fixed_div_floor_large_number() {
187 let env = Env::default();
188 let x: I256 = I256::from_i128(&env, i128::MAX);
189 let y: I256 = I256::from_i128(&env, 10i128.pow(27));
190 let denominator: I256 = I256::from_i128(&env, 10i128.pow(38));
191
192 let result = x.clone().fixed_div_floor(&env, &y, &denominator);
193
194 let expected_result = x.mul(&I256::from_i128(&env, 10i128.pow(11)));
195 assert_eq!(result, expected_result);
196 }
197
198 #[test]
199 #[should_panic(expected = "attempt to multiply with overflow")]
200 fn test_fixed_div_floor_phantom_overflow() {
201 let env = Env::default();
202 let x: I256 = I256::from_i128(&env, i128::MAX);
203 let y: I256 = I256::from_i128(&env, 10i128.pow(27));
204 let denominator: I256 = I256::from_i128(&env, 10i128.pow(39));
206
207 x.fixed_div_floor(&env, &y, &denominator);
208 }
209
210 #[test]
213 fn test_fixed_div_ceil_rounds_down() {
214 let env = Env::default();
215 let x: I256 = I256::from_i128(&env, 314_1592653);
216 let y: I256 = I256::from_i128(&env, 1_5391280);
217 let denominator: I256 = I256::from_i128(&env, 1_0000000);
218
219 let result = x.fixed_div_ceil(&env, &y, &denominator);
220
221 assert_eq!(result, I256::from_i128(&env, 204_1150998));
222 }
223
224 #[test]
225 fn test_fixed_div_ceil_negative_rounds_down() {
226 let env = Env::default();
227 let x: I256 = I256::from_i128(&env, 314_1592653);
228 let y: I256 = I256::from_i128(&env, -1_5391280);
229 let denominator: I256 = I256::from_i128(&env, 1_0000000);
230
231 let result = x.fixed_div_ceil(&env, &y, &denominator);
232
233 assert_eq!(result, I256::from_i128(&env, -204_1150997));
234 }
235
236 #[test]
237 fn test_fixed_div_ceil_large_number() {
238 let env = Env::default();
239 let x: I256 = I256::from_i128(&env, i128::MAX);
240 let y: I256 = I256::from_i128(&env, 10i128.pow(27));
241 let denominator: I256 = I256::from_i128(&env, 10i128.pow(38));
242
243 let result = x.clone().fixed_div_ceil(&env, &y, &denominator);
244
245 let expected_result = x.mul(&I256::from_i128(&env, 10i128.pow(11)));
246 assert_eq!(result, expected_result);
247 }
248
249 #[test]
250 #[should_panic(expected = "attempt to multiply with overflow")]
251 fn test_fixed_div_ceil_phantom_overflow() {
252 let env = Env::default();
253 let x: I256 = I256::from_i128(&env, i128::MAX);
254 let y: I256 = I256::from_i128(&env, 10i128.pow(27));
255 let denominator: I256 = I256::from_i128(&env, 10i128.pow(39));
257
258 x.fixed_div_ceil(&env, &y, &denominator);
259 }
260}