soroban_fixed_point_math/
u256.rs1use soroban_sdk::{Env, U256};
2
3use crate::soroban_fixed_point::SorobanFixedPoint;
4
5impl SorobanFixedPoint for U256 {
6 fn fixed_mul_floor(&self, _env: &Env, y: &U256, denominator: &U256) -> U256 {
7 mul_div_floor(self, y, denominator)
8 }
9
10 fn fixed_mul_ceil(&self, env: &Env, y: &U256, denominator: &U256) -> U256 {
11 mul_div_ceil(env, self, y, denominator)
12 }
13
14 fn fixed_div_floor(&self, _env: &Env, y: &U256, denominator: &U256) -> U256 {
15 mul_div_floor(self, denominator, y)
16 }
17
18 fn fixed_div_ceil(&self, env: &Env, y: &U256, denominator: &U256) -> U256 {
19 mul_div_ceil(env, self, denominator, y)
20 }
21}
22
23pub(crate) fn mul_div_floor(x: &U256, y: &U256, z: &U256) -> U256 {
25 x.mul(&y).div(&z)
27}
28
29pub(crate) fn mul_div_ceil(env: &Env, x: &U256, y: &U256, z: &U256) -> U256 {
31 let r = x.mul(&y);
32 let remainder = r.rem_euclid(&z);
33 let zero = U256::from_u32(env, 0);
34 let one = U256::from_u32(env, 1);
35 r.div(&z).add(if remainder > zero { &one } else { &zero })
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
45 fn test_fixed_mul_floor_rounds_down() {
46 let env = Env::default();
47 let x: U256 = U256::from_u128(&env, 1_5391283);
48 let y: U256 = U256::from_u128(&env, 314_1592653);
49 let denominator: U256 = U256::from_u128(&env, 1_0000001);
50
51 let result = x.fixed_mul_floor(&env, &y, &denominator);
52
53 assert_eq!(result, U256::from_u128(&env, 483_5313675));
54 }
55
56 #[test]
57 fn test_fixed_mul_floor_large_number() {
58 let env = Env::default();
59 let x: U256 = U256::from_u128(&env, u128::MAX);
60 let y: U256 = U256::from_u128(&env, 10u128.pow(38));
61 let denominator: U256 = U256::from_u128(&env, 10u128.pow(18));
62
63 let result = x.clone().fixed_mul_floor(&env, &y, &denominator);
64
65 let expected_result = x.mul(&U256::from_u128(&env, 10u128.pow(20)));
66 assert_eq!(result, expected_result);
67 }
68
69 #[test]
70 #[should_panic(expected = "attempt to multiply with overflow")]
71 fn test_fixed_mul_floor_phantom_overflow() {
72 let env = Env::default();
73 let x: U256 = U256::from_u128(&env, u128::MAX);
74 let y: U256 = U256::from_u128(&env, 10u128.pow(39));
76 let denominator: U256 = U256::from_u128(&env, 10u128.pow(18));
77
78 x.fixed_mul_floor(&env, &y, &denominator);
79 }
80
81 #[test]
84 fn test_fixed_mul_ceil_rounds_up() {
85 let env = Env::default();
86 let x: U256 = U256::from_u128(&env, 1_5391283);
87 let y: U256 = U256::from_u128(&env, 314_1592653);
88 let denominator: U256 = U256::from_u128(&env, 1_0000001);
89
90 let result = x.fixed_mul_ceil(&env, &y, &denominator);
91
92 assert_eq!(result, U256::from_u128(&env, 483_5313676));
93 }
94
95 #[test]
96 fn test_fixed_mul_ceil_large_number() {
97 let env = Env::default();
98 let x: U256 = U256::from_u128(&env, u128::MAX);
99 let y: U256 = U256::from_u128(&env, 10u128.pow(38));
100 let denominator: U256 = U256::from_u128(&env, 10u128.pow(18));
101
102 let result = x.clone().fixed_mul_ceil(&env, &y, &denominator);
103
104 let expected_result = x.mul(&U256::from_u128(&env, 10u128.pow(20)));
105 assert_eq!(result, expected_result);
106 }
107
108 #[test]
109 #[should_panic(expected = "attempt to multiply with overflow")]
110 fn test_fixed_mul_ceil_phantom_overflow() {
111 let env = Env::default();
112 let x: U256 = U256::from_u128(&env, u128::MAX);
113 let y: U256 = U256::from_u128(&env, 10u128.pow(39));
115 let denominator: U256 = U256::from_u128(&env, 10u128.pow(18));
116
117 x.fixed_mul_ceil(&env, &y, &denominator);
118 }
119
120 #[test]
123 fn test_fixed_div_floor_rounds_down() {
124 let env = Env::default();
125 let x: U256 = U256::from_u128(&env, 314_1592653);
126 let y: U256 = U256::from_u128(&env, 1_5391280);
127 let denominator: U256 = U256::from_u128(&env, 1_0000000);
128
129 let result = x.fixed_div_floor(&env, &y, &denominator);
130
131 assert_eq!(result, U256::from_u128(&env, 204_1150997));
132 }
133
134 #[test]
135 fn test_fixed_div_floor_large_number() {
136 let env = Env::default();
137 let x: U256 = U256::from_u128(&env, u128::MAX);
138 let y: U256 = U256::from_u128(&env, 10u128.pow(27));
139 let denominator: U256 = U256::from_u128(&env, 10u128.pow(38));
140
141 let result = x.clone().fixed_div_floor(&env, &y, &denominator);
142
143 let expected_result = x.mul(&U256::from_u128(&env, 10u128.pow(11)));
144 assert_eq!(result, expected_result);
145 }
146
147 #[test]
148 #[should_panic(expected = "attempt to multiply with overflow")]
149 fn test_fixed_div_floor_phantom_overflow() {
150 let env = Env::default();
151 let x: U256 = U256::from_u128(&env, u128::MAX);
152 let y: U256 = U256::from_u128(&env, 10u128.pow(27));
153 let denominator: U256 = U256::from_u128(&env, 10u128.pow(39));
155
156 x.fixed_div_floor(&env, &y, &denominator);
157 }
158
159 #[test]
162 fn test_fixed_div_ceil_rounds_down() {
163 let env = Env::default();
164 let x: U256 = U256::from_u128(&env, 314_1592653);
165 let y: U256 = U256::from_u128(&env, 1_5391280);
166 let denominator: U256 = U256::from_u128(&env, 1_0000000);
167
168 let result = x.fixed_div_ceil(&env, &y, &denominator);
169
170 assert_eq!(result, U256::from_u128(&env, 204_1150998));
171 }
172
173 #[test]
174 fn test_fixed_div_ceil_large_number() {
175 let env = Env::default();
176 let x: U256 = U256::from_u128(&env, u128::MAX);
177 let y: U256 = U256::from_u128(&env, 10u128.pow(27));
178 let denominator: U256 = U256::from_u128(&env, 10u128.pow(38));
179
180 let result = x.clone().fixed_div_ceil(&env, &y, &denominator);
181
182 let expected_result = x.mul(&U256::from_u128(&env, 10u128.pow(11)));
183 assert_eq!(result, expected_result);
184 }
185
186 #[test]
187 #[should_panic(expected = "attempt to multiply with overflow")]
188 fn test_fixed_div_ceil_phantom_overflow() {
189 let env = Env::default();
190 let x: U256 = U256::from_u128(&env, u128::MAX);
191 let y: U256 = U256::from_u128(&env, 10u128.pow(27));
192 let denominator: U256 = U256::from_u128(&env, 10u128.pow(39));
194
195 x.fixed_div_ceil(&env, &y, &denominator);
196 }
197}