balancer_maths_rust/common/
log_exp_math.rs1use crate::common::errors::PoolError;
3use alloy_primitives::{uint, I256, U256};
4use std::str::FromStr;
5
6pub const ONE_18: I256 = I256::from_raw(uint!(1000000000000000000_U256));
8pub const MAX_NATURAL_EXPONENT: I256 = I256::from_raw(uint!(130000000000000000000_U256));
9pub const LN_36_LOWER_BOUND: I256 = I256::from_raw(uint!(900000000000000000_U256));
10pub const LN_36_UPPER_BOUND: I256 = I256::from_raw(uint!(1100000000000000000_U256));
11pub const MILD_EXPONENT_BOUND: U256 =
13 uint!(289480223093290488558927462521719769633174961664101410098_U256);
14
15pub const RAY: I256 = I256::from_raw(uint!(1000000000000000000000000000000000000_U256));
17
18pub const X0: I256 = I256::from_raw(uint!(128000000000000000000_U256)); pub const A0: I256 = I256::from_raw(uint!(
21 38877084059945950922200000000000000000000000000000000000_U256
22)); pub const X1: I256 = I256::from_raw(uint!(64000000000000000000_U256)); pub const A1: I256 = I256::from_raw(uint!(6235149080811616882910000000_U256)); pub const X2: I256 = I256::from_raw(uint!(3200000000000000000000_U256)); pub const A2: I256 = I256::from_raw(uint!(7896296018268069516100000000000000_U256)); pub const X3: I256 = I256::from_raw(uint!(1600000000000000000000_U256)); pub const A3: I256 = I256::from_raw(uint!(888611052050787263676000000_U256)); pub const X4: I256 = I256::from_raw(uint!(800000000000000000000_U256)); pub const A4: I256 = I256::from_raw(uint!(298095798704172827474000_U256)); pub const X5: I256 = I256::from_raw(uint!(400000000000000000000_U256)); pub const A5: I256 = I256::from_raw(uint!(5459815003314423907810_U256)); pub const X6: I256 = I256::from_raw(uint!(200000000000000000000_U256)); pub const A6: I256 = I256::from_raw(uint!(738905609893065022723_U256)); pub const X7: I256 = I256::from_raw(uint!(100000000000000000000_U256)); pub const A7: I256 = I256::from_raw(uint!(271828182845904523536_U256)); pub const X8: I256 = I256::from_raw(uint!(50000000000000000000_U256)); pub const A8: I256 = I256::from_raw(uint!(164872127070012814685_U256)); pub const X9: I256 = I256::from_raw(uint!(25000000000000000000_U256)); pub const A9: I256 = I256::from_raw(uint!(128402541668774148407_U256)); pub const X10: I256 = I256::from_raw(uint!(12500000000000000000_U256)); pub const A10: I256 = I256::from_raw(uint!(113314845306682631683_U256)); pub const X11: I256 = I256::from_raw(uint!(6250000000000000000_U256)); pub const A11: I256 = I256::from_raw(uint!(106449445891785942956_U256)); pub const ONE_20: I256 = I256::from_raw(uint!(100000000000000000000_U256));
49
50const MIN_NATURAL_EXPONENT_ABS: U256 = uint!(41000000000000000000_U256);
52pub const MIN_NATURAL_EXPONENT: I256 =
53 I256::from_raw(U256::ZERO.wrapping_sub(MIN_NATURAL_EXPONENT_ABS));
54
55pub fn pow(x: &U256, y: &U256) -> Result<U256, PoolError> {
57 if y.is_zero() {
58 return Ok(ONE_18.into_raw());
60 }
61
62 if x.is_zero() {
63 return Ok(U256::ZERO);
64 }
65
66 let x_int256 = I256::from_raw(*x);
67
68 if y >= &MILD_EXPONENT_BOUND {
70 return Err(PoolError::MathOverflow);
71 }
72 let y_int256 = I256::from_raw(*y);
73
74 let logx_times_y = if x_int256 > LN_36_LOWER_BOUND && x_int256 < LN_36_UPPER_BOUND {
75 let ln_36_x = ln_36(&x_int256)?;
76 (ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18
81 } else {
82 ln(&x_int256)? * y_int256
83 };
84
85 let logx_times_y = logx_times_y / ONE_18;
86
87 if logx_times_y < MIN_NATURAL_EXPONENT || logx_times_y > MAX_NATURAL_EXPONENT {
89 return Err(PoolError::MathOverflow);
90 }
91
92 exp(&logx_times_y).map(|result| result.into_raw())
93}
94
95fn exp(x: &I256) -> Result<I256, PoolError> {
97 if x < &MIN_NATURAL_EXPONENT || x > &MAX_NATURAL_EXPONENT {
98 return Err(PoolError::MathOverflow);
99 }
100
101 if x.is_negative() {
102 return Ok((ONE_18 * ONE_18) / exp(&(-*x))?);
106 }
107
108 let mut x = *x;
109 let first_an = if x >= X0 {
110 x -= X0;
111 A0
112 } else if x >= X1 {
113 x -= X1;
114 A1
115 } else {
116 I256::ONE
117 };
118
119 x *= I256::from_str("100").unwrap();
122
123 let mut product = ONE_20;
126
127 if x >= X2 {
128 x -= X2;
129 product = (product * A2) / ONE_20;
130 }
131 if x >= X3 {
132 x -= X3;
133 product = (product * A3) / ONE_20;
134 }
135 if x >= X4 {
136 x -= X4;
137 product = (product * A4) / ONE_20;
138 }
139 if x >= X5 {
140 x -= X5;
141 product = (product * A5) / ONE_20;
142 }
143 if x >= X6 {
144 x -= X6;
145 product = (product * A6) / ONE_20;
146 }
147 if x >= X7 {
148 x -= X7;
149 product = (product * A7) / ONE_20;
150 }
151 if x >= X8 {
152 x -= X8;
153 product = (product * A8) / ONE_20;
154 }
155 if x >= X9 {
156 x -= X9;
157 product = (product * A9) / ONE_20;
158 }
159
160 let mut series_sum = ONE_20; let mut term = x; series_sum += term;
170
171 term = (term * x) / ONE_20 / I256::from_str("2").unwrap();
175 series_sum += term;
176
177 term = (term * x) / ONE_20 / I256::from_str("3").unwrap();
178 series_sum += term;
179
180 term = (term * x) / ONE_20 / I256::from_str("4").unwrap();
181 series_sum += term;
182
183 term = (term * x) / ONE_20 / I256::from_str("5").unwrap();
184 series_sum += term;
185
186 term = (term * x) / ONE_20 / I256::from_str("6").unwrap();
187 series_sum += term;
188
189 term = (term * x) / ONE_20 / I256::from_str("7").unwrap();
190 series_sum += term;
191
192 term = (term * x) / ONE_20 / I256::from_str("8").unwrap();
193 series_sum += term;
194
195 term = (term * x) / ONE_20 / I256::from_str("9").unwrap();
196 series_sum += term;
197
198 term = (term * x) / ONE_20 / I256::from_str("10").unwrap();
199 series_sum += term;
200
201 term = (term * x) / ONE_20 / I256::from_str("11").unwrap();
202 series_sum += term;
203
204 term = (term * x) / ONE_20 / I256::from_str("12").unwrap();
205 series_sum += term;
206
207 let result = ((product * series_sum) / ONE_20) * first_an / I256::from_str("100").unwrap();
212
213 Ok(result)
214}
215
216fn ln(x: &I256) -> Result<I256, PoolError> {
218 let mut a = *x;
219
220 if a < ONE_18 {
221 return Ok(I256::MINUS_ONE * ln(&((ONE_18 * ONE_18) / a))?);
225 }
226
227 let mut sum = I256::ZERO;
243 if a >= (A0 * ONE_18) {
244 a /= A0; sum += X0;
246 }
247
248 if a >= (A1 * ONE_18) {
249 a /= A1; sum += X1;
251 }
252
253 sum *= I256::from_str("100").unwrap();
255 a *= I256::from_str("100").unwrap();
256
257 if a >= A2 {
260 a = (a * ONE_20) / A2;
261 sum += X2;
262 }
263
264 if a >= A3 {
265 a = (a * ONE_20) / A3;
266 sum += X3;
267 }
268
269 if a >= A4 {
270 a = (a * ONE_20) / A4;
271 sum += X4;
272 }
273
274 if a >= A5 {
275 a = (a * ONE_20) / A5;
276 sum += X5;
277 }
278
279 if a >= A6 {
280 a = (a * ONE_20) / A6;
281 sum += X6;
282 }
283
284 if a >= A7 {
285 a = (a * ONE_20) / A7;
286 sum += X7;
287 }
288
289 if a >= A8 {
290 a = (a * ONE_20) / A8;
291 sum += X8;
292 }
293
294 if a >= A9 {
295 a = (a * ONE_20) / A9;
296 sum += X9;
297 }
298
299 if a >= A10 {
300 a = (a * ONE_20) / A10;
301 sum += X10;
302 }
303
304 if a >= A11 {
305 a = (a * ONE_20) / A11;
306 sum += X11;
307 }
308
309 let z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
317 let z_squared = (z * z) / ONE_20;
318
319 let mut num = z;
321
322 let mut series_sum = num;
324
325 num = (num * z_squared) / ONE_20;
327 series_sum += num / I256::from_str("3").unwrap();
328
329 num = (num * z_squared) / ONE_20;
330 series_sum += num / I256::from_str("5").unwrap();
331
332 num = (num * z_squared) / ONE_20;
333 series_sum += num / I256::from_str("7").unwrap();
334
335 num = (num * z_squared) / ONE_20;
336 series_sum += num / I256::from_str("9").unwrap();
337
338 num = (num * z_squared) / ONE_20;
339 series_sum += num / I256::from_str("11").unwrap();
340
341 series_sum *= I256::from_str("2").unwrap();
345
346 Ok((sum + series_sum) / I256::from_str("100").unwrap())
351}
352
353fn ln_36(x: &I256) -> Result<I256, PoolError> {
355 let mut x = *x;
356 x *= ONE_18;
361
362 let z = ((x - RAY) * RAY) / (x + RAY);
368 let z_squared = (z * z) / RAY;
369
370 let mut num = z;
372
373 let mut series_sum = num;
375
376 num = (num * z_squared) / RAY;
378 series_sum += num / I256::from_str("3").unwrap();
379
380 num = (num * z_squared) / RAY;
381 series_sum += num / I256::from_str("5").unwrap();
382
383 num = (num * z_squared) / RAY;
384 series_sum += num / I256::from_str("7").unwrap();
385
386 num = (num * z_squared) / RAY;
387 series_sum += num / I256::from_str("9").unwrap();
388
389 num = (num * z_squared) / RAY;
390 series_sum += num / I256::from_str("11").unwrap();
391
392 num = (num * z_squared) / RAY;
393 series_sum += num / I256::from_str("13").unwrap();
394
395 num = (num * z_squared) / RAY;
396 series_sum += num / I256::from_str("15").unwrap();
397
398 Ok(series_sum * I256::from_str("2").unwrap())
402}