balancer_maths_rust/common/
maths.rs1use crate::common::constants::{FOUR_WAD, MAX_POW_RELATIVE_ERROR, TWO_WAD, WAD};
4use crate::common::errors::PoolError;
5use crate::common::log_exp_math;
6use num_bigint::BigInt;
7use num_traits::{One, Zero};
8
9pub fn mul_up_fixed(a: &BigInt, b: &BigInt) -> Result<BigInt, PoolError> {
11 let product = a * b;
12 if product.is_zero() {
13 return Ok(BigInt::zero());
14 }
15 let result = (product - BigInt::one()) / &*WAD + BigInt::one();
16 Ok(result)
17}
18
19pub fn div_up_fixed(a: &BigInt, b: &BigInt) -> Result<BigInt, PoolError> {
21 if a.is_zero() {
22 return Ok(BigInt::zero());
23 }
24 if b.is_zero() {
25 return Err(PoolError::MathOverflow);
26 }
27
28 let a_inflated = a * &*WAD;
29 let result = (&a_inflated - BigInt::one()) / b + BigInt::one();
30 Ok(result)
31}
32
33pub fn mul_down_fixed(a: &BigInt, b: &BigInt) -> Result<BigInt, PoolError> {
35 let product = a * b;
36 let result = product / &*WAD;
37 Ok(result)
38}
39
40pub fn div_down_fixed(a: &BigInt, b: &BigInt) -> Result<BigInt, PoolError> {
42 if a.is_zero() {
43 return Ok(BigInt::zero());
44 }
45 if b.is_zero() {
46 return Err(PoolError::MathOverflow);
47 }
48
49 let a_inflated = a * &*WAD;
50 let result = a_inflated / b;
51 Ok(result)
52}
53
54pub fn div_up(a: &BigInt, b: &BigInt) -> Result<BigInt, PoolError> {
56 if b.is_zero() {
57 return Ok(BigInt::zero());
58 }
59 let result = BigInt::one() + (a - &BigInt::one()) / b;
60 Ok(result)
61}
62
63pub fn mul_div_up_fixed(a: &BigInt, b: &BigInt, c: &BigInt) -> Result<BigInt, PoolError> {
65 let product = a * b;
66 let result = (&product - &BigInt::one()) / c + &BigInt::one();
67 Ok(result)
68}
69
70pub fn pow_down_fixed(base: &BigInt, exponent: &BigInt) -> Result<BigInt, PoolError> {
72 pow_down_fixed_with_version(base, exponent, 0)
73}
74
75pub fn pow_down_fixed_with_version(
77 base: &BigInt,
78 exponent: &BigInt,
79 version: u32,
80) -> Result<BigInt, PoolError> {
81 if exponent == &*WAD && version != 1 {
82 return Ok(base.clone());
83 }
84 if exponent == &*TWO_WAD && version != 1 {
85 return mul_up_fixed(base, base);
86 }
87 if exponent == &*FOUR_WAD && version != 1 {
88 let square = mul_up_fixed(base, base)?;
89 return mul_up_fixed(&square, &square);
90 }
91
92 let raw = log_exp_math::pow(base, exponent)?;
93 let max_error = mul_up_fixed(&raw, &MAX_POW_RELATIVE_ERROR)? + &BigInt::one();
94
95 if raw < max_error {
96 return Ok(BigInt::zero());
97 }
98
99 Ok(raw - max_error)
100}
101
102pub fn pow_up_fixed(base: &BigInt, exponent: &BigInt) -> Result<BigInt, PoolError> {
104 pow_up_fixed_with_version(base, exponent, 0)
105}
106
107pub fn pow_up_fixed_with_version(
109 base: &BigInt,
110 exponent: &BigInt,
111 version: u32,
112) -> Result<BigInt, PoolError> {
113 if exponent == &*WAD && version != 1 {
114 return Ok(base.clone());
115 }
116 if exponent == &*TWO_WAD && version != 1 {
117 return mul_up_fixed(base, base);
118 }
119 if exponent == &*FOUR_WAD && version != 1 {
120 let square = mul_up_fixed(base, base)?;
121 return mul_up_fixed(&square, &square);
122 }
123
124 let raw = log_exp_math::pow(base, exponent)?;
125 let max_error = mul_up_fixed(&raw, &MAX_POW_RELATIVE_ERROR)? + &BigInt::one();
126
127 Ok(raw + max_error)
128}
129
130pub fn complement_fixed(x: &BigInt) -> Result<BigInt, PoolError> {
132 if x < &*WAD {
133 Ok(&*WAD - x)
134 } else {
135 Ok(BigInt::zero())
136 }
137}