From 4f0b4dc22bfb16e36778f967b966418791449237 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Thu, 19 Oct 2023 12:21:39 -0400 Subject: [PATCH 01/26] cleaned up codes --- .../src/exchange_mock_querier.rs | 16 ++--- .../src/fp_decimal/arithmetic.rs | 67 ++++++++++--------- .../injective-math/src/fp_decimal/display.rs | 2 +- packages/injective-math/src/fp_decimal/exp.rs | 54 +++++++-------- packages/injective-math/src/fp_decimal/log.rs | 10 +-- packages/injective-math/src/fp_decimal/mod.rs | 51 ++++---------- .../injective-math/src/fp_decimal/scale.rs | 2 +- packages/injective-math/src/utils.rs | 40 ++++++----- packages/injective-math/src/vector.rs | 9 +-- 9 files changed, 116 insertions(+), 135 deletions(-) diff --git a/packages/injective-cosmwasm/src/exchange_mock_querier.rs b/packages/injective-cosmwasm/src/exchange_mock_querier.rs index 6335af66..7395488a 100644 --- a/packages/injective-cosmwasm/src/exchange_mock_querier.rs +++ b/packages/injective-cosmwasm/src/exchange_mock_querier.rs @@ -106,7 +106,7 @@ fn default_derivative_market_response_handler(market_id: MarketId) -> QuerierRes min_quantity_tick_size: FPDecimal::from_str("0.0001").unwrap(), }), info: None, - mark_price: FPDecimal::one(), + mark_price: FPDecimal::ONE, }), }; SystemResult::Ok(ContractResult::from(to_binary(&response))) @@ -153,7 +153,7 @@ fn default_perpetual_market_funding_response_handler() -> QuerierResult { fn default_market_volatility_response_handler() -> QuerierResult { let response = MarketVolatilityResponse { - volatility: Some(FPDecimal::one()), + volatility: Some(FPDecimal::ONE), history_metadata: None, raw_history: None, }; @@ -222,7 +222,7 @@ fn default_denom_decimals_handler() -> QuerierResult { fn default_oracle_volatility_response_handler() -> QuerierResult { let response = OracleVolatilityResponse { - volatility: Some(FPDecimal::one()), + volatility: Some(FPDecimal::ONE), history_metadata: None, raw_history: None, }; @@ -233,13 +233,13 @@ fn default_pyth_price_response_handler() -> QuerierResult { let response = PythPriceResponse { price_state: Some(PythPriceState { price_id: "0xff0ec26442c57d7456695b843694e7379b15cf1b250b27e0e47e657f1955aaff".to_string(), - ema_price: FPDecimal::one(), - ema_conf: FPDecimal::one(), - conf: FPDecimal::one(), + ema_price: FPDecimal::ONE, + ema_conf: FPDecimal::ONE, + conf: FPDecimal::ONE, publish_time: 1i64, price_state: PriceState { - price: FPDecimal::one(), - cumulative_price: FPDecimal::one(), + price: FPDecimal::ONE, + cumulative_price: FPDecimal::ONE, timestamp: 1i64, }, }), diff --git a/packages/injective-math/src/fp_decimal/arithmetic.rs b/packages/injective-math/src/fp_decimal/arithmetic.rs index 7cdbcd4b..fbb4120e 100644 --- a/packages/injective-math/src/fp_decimal/arithmetic.rs +++ b/packages/injective-math/src/fp_decimal/arithmetic.rs @@ -18,12 +18,14 @@ impl FPDecimal { sign: x.sign, }; } - let mut sign = y.sign; if y.num == x.num { - sign = 1; + return FPDecimal::ZERO; } - FPDecimal { num: y.num - x.num, sign } + FPDecimal { + num: y.num - x.num, + sign: y.sign, + } } pub fn add(&self, other: i128) -> FPDecimal { @@ -79,7 +81,7 @@ impl FPDecimal { let num = FPDecimal::ONE.num.full_mul(x.num) / y.num.into(); if num.is_zero() { - return FPDecimal::zero(); + return FPDecimal::ZERO; } FPDecimal { @@ -88,11 +90,11 @@ impl FPDecimal { } } - pub fn div(&self, other: i128) -> FPDecimal { + pub fn div(&self, other: i128) -> Self { FPDecimal::_div(*self, FPDecimal::from(other)) } - pub fn reciprocal(x: FPDecimal) -> FPDecimal { + pub fn reciprocal(x: FPDecimal) -> Self { assert!(x.num != U256::zero()); FPDecimal { num: FPDecimal::ONE.num * FPDecimal::ONE.num / x.num, @@ -100,7 +102,7 @@ impl FPDecimal { } } - pub fn abs(&self) -> FPDecimal { + pub fn abs(&self) -> Self { FPDecimal { num: self.num, sign: 1i8 } } @@ -239,7 +241,6 @@ impl<'a> iter::Sum<&'a Self> for FPDecimal { #[cfg(test)] mod tests { - use std::str::FromStr; use crate::FPDecimal; use bigint::U256; @@ -354,65 +355,65 @@ mod tests { fn test_mul_precisions() { // 8.33157469 * 0.000000000001 = 0.00000000000833157469 assert_eq!( - FPDecimal::from_str("8.33157469").unwrap() * FPDecimal::from_str("0.000000000001").unwrap(), - FPDecimal::from_str("0.000000000008331574").unwrap() + FPDecimal::must_from_str("8.33157469") * FPDecimal::must_from_str("0.000000000001"), + FPDecimal::must_from_str("0.000000000008331574") ); // 1.5 * 1.5 = 2.25 assert_eq!( - FPDecimal::from_str("1.5").unwrap() * FPDecimal::from_str("1.5").unwrap(), - FPDecimal::from_str("2.25").unwrap() + FPDecimal::must_from_str("1.5") * FPDecimal::must_from_str("1.5"), + FPDecimal::must_from_str("2.25") ); // 2.718281828459045235 * 2.718281828459045235 = 7.389056098930650225 - assert_eq!(FPDecimal::E * FPDecimal::E, FPDecimal::from_str("7.389056098930650225").unwrap()); + assert_eq!(FPDecimal::E * FPDecimal::E, FPDecimal::must_from_str("7.389056098930650225")); // 0.5 * 0.5 = 0.25 assert_eq!( - FPDecimal::from_str("0.5").unwrap() * FPDecimal::from_str("0.5").unwrap(), - FPDecimal::from_str("0.25").unwrap() + FPDecimal::must_from_str("0.5") * FPDecimal::must_from_str("0.5"), + FPDecimal::must_from_str("0.25") ); // 5 * 0.5 = 2.5 - assert_eq!(FPDecimal::FIVE * FPDecimal::from_str("0.5").unwrap(), FPDecimal::from_str("2.5").unwrap()); + assert_eq!(FPDecimal::FIVE * FPDecimal::must_from_str("0.5"), FPDecimal::must_from_str("2.5")); // 0.5 * 5 = 2.5 - assert_eq!(FPDecimal::from_str("0.5").unwrap() * FPDecimal::FIVE, FPDecimal::from_str("2.5").unwrap()); + assert_eq!(FPDecimal::must_from_str("0.5") * FPDecimal::FIVE, FPDecimal::must_from_str("2.5")); // 4 * 2.5 = 10 - assert_eq!(FPDecimal::FOUR * FPDecimal::from_str("2.5").unwrap(), FPDecimal::from_str("10").unwrap()); + assert_eq!(FPDecimal::FOUR * FPDecimal::must_from_str("2.5"), FPDecimal::must_from_str("10")); // 2.5 * 4 = 10 - assert_eq!(FPDecimal::from_str("2.5").unwrap() * FPDecimal::FOUR, FPDecimal::from_str("10").unwrap()); + assert_eq!(FPDecimal::must_from_str("2.5") * FPDecimal::FOUR, FPDecimal::must_from_str("10")); // 0.000000008 * 0.9 = 0.0000000072 assert_eq!( - FPDecimal::from_str("0.000000008").unwrap() * FPDecimal::from_str("0.9").unwrap(), - FPDecimal::from_str("0.0000000072").unwrap() + FPDecimal::must_from_str("0.000000008") * FPDecimal::must_from_str("0.9"), + FPDecimal::must_from_str("0.0000000072") ); // 0.0000000008 * 0.9 = 0.00000000072 assert_eq!( - FPDecimal::from_str("0.0000000008").unwrap() * FPDecimal::from_str("0.9").unwrap(), - FPDecimal::from_str("0.00000000072").unwrap() + FPDecimal::must_from_str("0.0000000008") * FPDecimal::must_from_str("0.9"), + FPDecimal::must_from_str("0.00000000072") ); // -0.5 * 0.5 = -0.25 assert_eq!( - FPDecimal::from_str("-0.5").unwrap() * FPDecimal::from_str("0.5").unwrap(), - FPDecimal::from_str("-0.25").unwrap() + FPDecimal::must_from_str("-0.5") * FPDecimal::must_from_str("0.5"), + FPDecimal::must_from_str("-0.25") ); // -0.5 * -0.5 = 0.25 assert_eq!( - FPDecimal::from_str("-0.5").unwrap() * FPDecimal::from_str("-0.5").unwrap(), - FPDecimal::from_str("0.25").unwrap() + FPDecimal::must_from_str("-0.5") * FPDecimal::must_from_str("-0.5"), + FPDecimal::must_from_str("0.25") ); // -5 * -3 = 15 assert_eq!( - FPDecimal::from_str("-5").unwrap() * FPDecimal::from_str("-3").unwrap(), - FPDecimal::from_str("15").unwrap() + FPDecimal::must_from_str("-5") * FPDecimal::must_from_str("-3"), + FPDecimal::must_from_str("15") ); } @@ -568,7 +569,7 @@ mod tests { }; five -= four; let one = five; - assert_eq!(one, FPDecimal::one()); + assert_eq!(one, FPDecimal::ONE); let mut one = one; let five = FPDecimal { @@ -635,7 +636,7 @@ mod tests { let val = FPDecimal::TWO; assert!(!val.is_negative()); - let val = FPDecimal::zero(); + let val = FPDecimal::ZERO; assert!(!val.is_negative()); // even a manually assigned negative zero value returns positive @@ -654,10 +655,10 @@ mod tests { let lhs = FPDecimal::from(2u128); let rhs = FPDecimal::from(3u128); let ans = lhs.abs_diff(&rhs); - assert_eq!(FPDecimal::one(), ans); + assert_eq!(FPDecimal::ONE, ans); let lhs = FPDecimal::from(3u128); - let rhs = FPDecimal::one(); + let rhs = FPDecimal::ONE; let ans = lhs.abs_diff(&rhs); assert_eq!(FPDecimal::from(2u128), ans); diff --git a/packages/injective-math/src/fp_decimal/display.rs b/packages/injective-math/src/fp_decimal/display.rs index c843675f..20426668 100644 --- a/packages/injective-math/src/fp_decimal/display.rs +++ b/packages/injective-math/src/fp_decimal/display.rs @@ -7,7 +7,7 @@ impl fmt::Display for FPDecimal { let integer = self.int().abs(); let fraction = (FPDecimal::_fraction(*self)).abs(); - if fraction == FPDecimal::zero() { + if fraction == FPDecimal::ZERO { write!(f, "{}{}", sign, integer.num / FPDecimal::ONE.num) } else { let fraction_string = fraction.num.to_string(); // diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index dac9aaf8..713c17b8 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -32,7 +32,7 @@ impl FPDecimal { // otherwise if there is a long enough delay between updates on a cluster // the penalty function will be bricked if a.sign == 0 && a.num >= FPDecimal::from(45i128).num { - return FPDecimal::zero(); + return FPDecimal::ZERO; } let mut x = a.num; let mut r = FPDecimal::ONE; @@ -46,7 +46,7 @@ impl FPDecimal { return FPDecimal::reciprocal(val); } return val; - } else if x == FPDecimal::zero().num { + } else if x == FPDecimal::ZERO.num { let val = r; if a.sign == 0 { return FPDecimal::reciprocal(val); @@ -70,17 +70,17 @@ impl FPDecimal { pub fn _sqrt(a: FPDecimal) -> Option { const MAX_ITERATIONS: i64 = 300; - if a < FPDecimal::zero() { + if a < FPDecimal::ZERO { return None; } if a.is_zero() { - return Some(FPDecimal::zero()); + return Some(FPDecimal::ZERO); } // Start with an arbitrary number as the first guess let mut r = a / FPDecimal::TWO; - let mut l = r + FPDecimal::one(); + let mut l = r + FPDecimal::ONE; // Keep going while the difference is larger than the tolerance let mut c = 0i64; @@ -104,11 +104,11 @@ impl FPDecimal { // This uses the exponentiation by squaring algorithm: // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method - if self == FPDecimal::zero() { - return Ok(FPDecimal::zero()); + if self == FPDecimal::ZERO { + return Ok(FPDecimal::ZERO); } - if self > FPDecimal::zero() && exponent == FPDecimal::zero() { - return Ok(FPDecimal::one()); + if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { + return Ok(FPDecimal::ONE); } if exponent > FPDecimal::from(60u128) { @@ -176,7 +176,7 @@ impl FPDecimal { } if self == FPDecimal::from(10u128) { - if exponent == FPDecimal::one() { + if exponent == FPDecimal::ONE { return Ok(FPDecimal::from(10u128)); } if exponent == FPDecimal::TWO { @@ -291,7 +291,7 @@ impl FPDecimal { return Ok(FPDecimal::from_str("0.000000000000000001").unwrap()); } if exponent < FPDecimal::from_str("-18").unwrap() { - return Ok(FPDecimal::zero()); + return Ok(FPDecimal::ZERO); } if exponent == FPDecimal::from(21u128) { return Ok(FPDecimal::from(1000000000000000000000u128)); @@ -418,7 +418,7 @@ impl FPDecimal { // 14 terms taylor expansion provides a good enough approximation const N_TERMS: u128 = 13; match exponent.cmp(&FPDecimal::ZERO) { - Ordering::Equal => Ok(FPDecimal::one()), + Ordering::Equal => Ok(FPDecimal::ONE), // Negative exponent Ordering::Less => { exponent = -exponent; @@ -445,7 +445,7 @@ impl FPDecimal { float_exp = FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, rem_b, n_terms); } let mut tmp_a = FPDecimal::ONE; - while int_b > FPDecimal::one() { + while int_b > FPDecimal::ONE { if int_b.num % FPDecimal::TWO.num == FPDecimal::ONE.num { tmp_a = base * tmp_a; int_b -= FPDecimal::ONE; @@ -584,7 +584,7 @@ impl FPDecimal { fn compute_integer_exponentiation(mut base: FPDecimal, mut exponent: FPDecimal) -> FPDecimal { let mut temp_base = FPDecimal::ONE; - while exponent > FPDecimal::one() { + while exponent > FPDecimal::ONE { if exponent.num % FPDecimal::TWO.num == FPDecimal::ONE.num { temp_base = base * temp_base; exponent -= FPDecimal::ONE; @@ -625,10 +625,10 @@ impl FPDecimal { // This uses the exponentiation by squaring algorithm: // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method - if self == FPDecimal::zero() { - return Ok(FPDecimal::zero()); + if self == FPDecimal::ZERO { + return Ok(FPDecimal::ZERO); } - if self.is_negative() && exponent == FPDecimal::zero() { + if self.is_negative() && exponent == FPDecimal::ZERO { return Ok(FPDecimal::NEGATIVE_ONE); } if exponent > FPDecimal::from(60u128) { @@ -811,7 +811,7 @@ impl FPDecimal { return Ok(FPDecimal::from_str("0.000000000000000001").unwrap()); } if exponent < FPDecimal::from_str("-18").unwrap() { - return Ok(FPDecimal::zero()); + return Ok(FPDecimal::ZERO); } if exponent == FPDecimal::from(21u128) { @@ -938,7 +938,7 @@ impl FPDecimal { // 14 terms taylor expansion provides a good enough approximation const N_TERMS: u128 = 13; match exponent.cmp(&FPDecimal::ZERO) { - Ordering::Equal => Ok(FPDecimal::one()), + Ordering::Equal => Ok(FPDecimal::ONE), Ordering::Less => { exponent = -exponent; match exponent.cmp(&(FPDecimal::ONE)) { @@ -1065,7 +1065,7 @@ impl FPDecimal { fn compute_integer_exponentiation(mut base: FPDecimal, mut exponent: FPDecimal) -> FPDecimal { let mut temp_base = FPDecimal::ONE; - while exponent > FPDecimal::one() { + while exponent > FPDecimal::ONE { if exponent.num % FPDecimal::TWO.num == FPDecimal::ONE.num { temp_base = base * temp_base; exponent -= FPDecimal::ONE; @@ -1122,7 +1122,7 @@ mod tests { #[test] fn test_exp0() { - assert_eq!(FPDecimal::_exp(FPDecimal::zero()), FPDecimal::ONE); + assert_eq!(FPDecimal::_exp(FPDecimal::ZERO), FPDecimal::ONE); } #[test] @@ -1138,7 +1138,7 @@ mod tests { #[test] fn test_pow_zero() { - FPDecimal::pow(FPDecimal::zero(), FPDecimal::one().div(2i128)); + FPDecimal::pow(FPDecimal::ZERO, FPDecimal::ONE.div(2i128)); assert_eq!(FPDecimal::ZERO.pow(FPDecimal::ONE), FPDecimal::ZERO); } @@ -1290,7 +1290,7 @@ mod tests { #[test] fn test_pow_exp0() { - assert_eq!(FPDecimal::E.pow(FPDecimal::zero()), FPDecimal::ONE); + assert_eq!(FPDecimal::E.pow(FPDecimal::ZERO), FPDecimal::ONE); } #[test] @@ -1306,7 +1306,7 @@ mod tests { #[test] fn test_pow_zero_2() { - FPDecimal::ZERO.pow(FPDecimal::one().div(2i128)); + FPDecimal::ZERO.pow(FPDecimal::ONE.div(2i128)); } #[test] @@ -1314,8 +1314,8 @@ mod tests { let inputs: Vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 25, -1]; let expected: Vec> = vec![ - Some(FPDecimal::zero()), - Some(FPDecimal::one()), + Some(FPDecimal::ZERO), + Some(FPDecimal::ONE), Some(FPDecimal::from_str("1.414213562373095048").unwrap()), Some(FPDecimal::from_str("1.732050807568877293").unwrap()), Some(FPDecimal::TWO), @@ -1395,7 +1395,7 @@ mod tests { #[test] fn test_pow_10_underflow() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow(FPDecimal::from_str("-19").unwrap()), FPDecimal::zero()); + assert_eq!(base.pow(FPDecimal::from_str("-19").unwrap()), FPDecimal::ZERO); } #[test] diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 68d487b6..3d389b3b 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -8,7 +8,7 @@ impl FPDecimal { } if let Some(value) = self._log_e() { - //NOTE: base e can't be represented by u128, so we 27 in here + //NOTE: base e can't be represented by u128, so we use 27 in here return Some((value, 27u128)); } if let Some(value) = self._log3() { @@ -521,9 +521,9 @@ impl FPDecimal { #[allow(clippy::many_single_char_names)] pub fn _ln(a: FPDecimal) -> FPDecimal { assert!(a.sign != 0); - assert!(a != FPDecimal::zero()); + assert!(a != FPDecimal::ZERO); let mut v = a.num; - let mut r = FPDecimal::zero(); + let mut r = FPDecimal::ZERO; while v <= FPDecimal::ONE.num / U256([10, 0, 0, 0]) { v = v * U256([10, 0, 0, 0]); r -= FPDecimal::LN_10; @@ -630,9 +630,9 @@ mod tests { #[test] fn test_ln_sanity() { - let half = FPDecimal::one().div(2i128); + let half = FPDecimal::ONE.div(2i128); println!("{}", FPDecimal::_ln(half)); // works if you comment this out - let num = FPDecimal::one().mul(5).div(4); + let num = FPDecimal::ONE.mul(5).div(4); println!("{}", FPDecimal::checked_positive_pow(num, half).unwrap()); } diff --git a/packages/injective-math/src/fp_decimal/mod.rs b/packages/injective-math/src/fp_decimal/mod.rs index 3a55d315..bb2ffe79 100644 --- a/packages/injective-math/src/fp_decimal/mod.rs +++ b/packages/injective-math/src/fp_decimal/mod.rs @@ -189,39 +189,32 @@ impl FPDecimal { sign: 1, }; + pub const E: FPDecimal = FPDecimal { + // 1_000_000_000_000_000_000 + num: U256([2_718_281_828_459_045_235, 0, 0, 0]), + sign: 1, + }; + pub const E_10: FPDecimal = FPDecimal { num: U256([1053370797511854089u64, 1194u64, 0, 0]), sign: 1, }; // e^10 - pub const E: FPDecimal = FPDecimal { - num: U256([2718281828459045235, 0, 0, 0]), + pub const LN_1_5: FPDecimal = FPDecimal { + num: U256([405465108108164382, 0, 0, 0]), sign: 1, - }; + }; // ln(1.5) pub const LN_10: FPDecimal = FPDecimal { num: U256([2302585092994045684, 0, 0, 0]), sign: 1, }; // ln(10) - pub const LN_1_5: FPDecimal = FPDecimal { - num: U256([405465108108164382, 0, 0, 0]), - sign: 1, - }; // ln(1.5) - pub const PI: FPDecimal = FPDecimal { num: U256([3_141_592_653_589_793_238, 0, 0, 0]), sign: 1, }; - pub const fn one() -> FPDecimal { - FPDecimal::ONE - } - - pub const fn zero() -> FPDecimal { - FPDecimal::ZERO - } - pub fn is_zero(&self) -> bool { self.num.is_zero() } @@ -235,37 +228,21 @@ impl FPDecimal { self.sign == 0 } - pub const fn max() -> FPDecimal { - FPDecimal::MAX - } - - pub const fn min() -> FPDecimal { - FPDecimal::MIN - } - - pub const fn e() -> FPDecimal { - FPDecimal::E - } - - pub fn _int(x: FPDecimal) -> FPDecimal { + pub fn _int(x: FPDecimal) -> Self { let x1 = x.num; let x1_1 = x1 / FPDecimal::ONE.num; let x_final = x1_1 * FPDecimal::ONE.num; FPDecimal { num: x_final, sign: x.sign } } - pub fn int(&self) -> FPDecimal { + pub fn int(&self) -> Self { FPDecimal::_int(*self) } pub fn is_int(&self) -> bool { *self == self.int() } - pub fn _sign(x: FPDecimal) -> i8 { - x.sign - } - - pub fn _fraction(x: FPDecimal) -> FPDecimal { + pub fn _fraction(x: FPDecimal) -> Self { let x1 = x.num; FPDecimal { num: x1 - FPDecimal::_int(x).num, @@ -273,7 +250,7 @@ impl FPDecimal { } } - pub fn fraction(&self) -> FPDecimal { + pub fn fraction(&self) -> Self { FPDecimal::_fraction(*self) } @@ -395,7 +372,7 @@ mod tests { assert_eq!(decimal_valid.to_string(), fp_decimal_valid.to_string()); // Test a valid zero value - let fp_decimal_zero = FPDecimal::zero(); + let fp_decimal_zero = FPDecimal::ZERO; let decimal_zero = Decimal256::try_from(fp_decimal_zero).unwrap(); assert_eq!(decimal_zero.to_string(), "0"); diff --git a/packages/injective-math/src/fp_decimal/scale.rs b/packages/injective-math/src/fp_decimal/scale.rs index 0dc7564b..e72196f4 100644 --- a/packages/injective-math/src/fp_decimal/scale.rs +++ b/packages/injective-math/src/fp_decimal/scale.rs @@ -11,7 +11,7 @@ impl Scaled for FPDecimal { } pub fn dec_scale_factor() -> FPDecimal { - FPDecimal::one().scaled(18) + FPDecimal::ONE.scaled(18) } #[cfg(test)] diff --git a/packages/injective-math/src/utils.rs b/packages/injective-math/src/utils.rs index d208b8d3..c33582a2 100644 --- a/packages/injective-math/src/utils.rs +++ b/packages/injective-math/src/utils.rs @@ -14,7 +14,7 @@ pub enum RangeEnds { } pub fn parse_dec(vs: &str, min: Option<&FPDecimal>, max: Option<&FPDecimal>, range_ends: RangeEnds) -> Result { - let v = FPDecimal::from_str(vs)?; + let v = FPDecimal::must_from_str(vs); ensure_band(&v, min, max, range_ends)?; Ok(v) } @@ -69,7 +69,7 @@ pub fn band_error_to_human(err: StdError, value_name: &str) -> StdError { } pub fn div_dec(num: FPDecimal, denom: FPDecimal) -> FPDecimal { - if denom == FPDecimal::zero() { + if denom == FPDecimal::ZERO { denom } else { num / denom @@ -104,7 +104,7 @@ pub fn round(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { pub fn round_to_min_tick(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { if num < min_tick { - FPDecimal::zero() + FPDecimal::ZERO } else { let shifted = div_dec(num, min_tick).int(); shifted * min_tick @@ -113,7 +113,7 @@ pub fn round_to_min_tick(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { pub fn round_to_nearest_tick(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { if num < min_tick { - return FPDecimal::zero(); + return FPDecimal::ZERO; } let remainder = FPDecimal::from(num.num % min_tick.num); @@ -275,6 +275,14 @@ mod tests { round_to_nearest_tick(FPDecimal::must_from_str("2.5"), FPDecimal::must_from_str("2.0")), FPDecimal::must_from_str("2.0") ); + assert_eq!( + round_to_nearest_tick( + FPDecimal::must_from_str("0.000000057575228461"), + FPDecimal::must_from_str("0.00000000000001") + ), + FPDecimal::must_from_str("0.00000005757523") + ); + assert_eq!( round_to_nearest_tick(FPDecimal::must_from_str("10.0"), FPDecimal::must_from_str("3.0")), FPDecimal::must_from_str("9.0") @@ -287,11 +295,11 @@ mod tests { ["1.009932", "1.01"], ["0.9932", "0.99"], ]; - let precision = FPDecimal::from_str("0.01").unwrap(); + let precision = FPDecimal::must_from_str("0.01"); for item in &data { - let input = FPDecimal::from_str(item[0]).unwrap(); - let expected = FPDecimal::from_str(item[1]).unwrap(); + let input = FPDecimal::must_from_str(item[0]); + let expected = FPDecimal::must_from_str(item[1]); let output = round_to_nearest_tick(input, precision); assert_eq!(expected, output); @@ -306,22 +314,22 @@ mod tests { let result = round_up_to_min_tick(num, min_tick); assert_eq!(result, FPDecimal::from(40u128)); - let num = FPDecimal::from_str("0.00000153").unwrap(); - let min_tick = FPDecimal::from_str("0.000001").unwrap(); + let num = FPDecimal::must_from_str("0.00000153"); + let min_tick = FPDecimal::must_from_str("0.000001"); let result = round_up_to_min_tick(num, min_tick); - assert_eq!(result, FPDecimal::from_str("0.000002").unwrap()); + assert_eq!(result, FPDecimal::must_from_str("0.000002")); - let num = FPDecimal::from_str("0.000001").unwrap(); - let min_tick = FPDecimal::from_str("0.000001").unwrap(); + let num = FPDecimal::must_from_str("0.000001"); + let min_tick = FPDecimal::must_from_str("0.000001"); let result = round_up_to_min_tick(num, min_tick); - assert_eq!(result, FPDecimal::from_str("0.000001").unwrap()); + assert_eq!(result, FPDecimal::must_from_str("0.000001")); - let num = FPDecimal::from_str("0.0000001").unwrap(); - let min_tick = FPDecimal::from_str("0.000001").unwrap(); + let num = FPDecimal::must_from_str("0.0000001"); + let min_tick = FPDecimal::must_from_str("0.000001"); let result = round_up_to_min_tick(num, min_tick); - assert_eq!(result, FPDecimal::from_str("0.000001").unwrap()); + assert_eq!(result, FPDecimal::must_from_str("0.000001")); } } diff --git a/packages/injective-math/src/vector.rs b/packages/injective-math/src/vector.rs index 67f562d2..22b1cf0e 100644 --- a/packages/injective-math/src/vector.rs +++ b/packages/injective-math/src/vector.rs @@ -1,16 +1,11 @@ use crate::fp_decimal::FPDecimal; pub fn sum(vec: &[FPDecimal]) -> FPDecimal { - vec.iter().fold(FPDecimal::zero(), |acc, &el| acc + el) + vec.iter().fold(FPDecimal::ZERO, |acc, &el| acc + el) } pub fn dot(vec: &[FPDecimal], other: &[FPDecimal]) -> FPDecimal { - let mut sum = FPDecimal::zero(); - let mul_result: Vec = mul(vec, other); - for item in mul_result { - sum += item; - } - sum + mul(vec, other).iter().sum() } pub fn mul(vec: &[FPDecimal], other: &[FPDecimal]) -> Vec { From 15368fe54fcc1680e46697efdbcc7ed02b83bdd6 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Fri, 20 Oct 2023 11:14:18 -0400 Subject: [PATCH 02/26] clean up arithmetic --- packages/injective-math/Cargo.toml | 3 +- .../src/fp_decimal/arithmetic.rs | 351 ++++++------------ 2 files changed, 116 insertions(+), 238 deletions(-) diff --git a/packages/injective-math/Cargo.toml b/packages/injective-math/Cargo.toml index 4fc85b17..a45ebf51 100644 --- a/packages/injective-math/Cargo.toml +++ b/packages/injective-math/Cargo.toml @@ -15,12 +15,13 @@ version = "0.1.23" backtraces = [ "cosmwasm-std/backtraces" ] [dependencies] -bigint = "4" +primitive-types = "0.12.2" cosmwasm-std = { version = "1.4.1" } ethereum-types = "0.5.2" schemars = "0.8.8" serde = { version = "1.0.136", default-features = false, features = [ "derive" ] } subtle-encoding = { version = "0.5.1", features = [ "bech32-preview" ] } +#num-traits = "0.2.17" [dev-dependencies] cosmwasm-schema = { version = "1.4.1" } diff --git a/packages/injective-math/src/fp_decimal/arithmetic.rs b/packages/injective-math/src/fp_decimal/arithmetic.rs index fbb4120e..5693d878 100644 --- a/packages/injective-math/src/fp_decimal/arithmetic.rs +++ b/packages/injective-math/src/fp_decimal/arithmetic.rs @@ -1,5 +1,7 @@ /// Arithmetic operators for FPDecimal use crate::fp_decimal::{FPDecimal, U256}; +use core::convert::TryFrom; +use primitive_types::U512; use std::iter; use std::ops; @@ -49,10 +51,10 @@ impl FPDecimal { if x.sign != y.sign { sign = 0; } - let x1: U256 = FPDecimal::_int(x).num / FPDecimal::ONE.num; - let x2: U256 = FPDecimal::_fraction(x).num; - let y1: U256 = FPDecimal::_int(y).num / FPDecimal::ONE.num; - let y2: U256 = FPDecimal::_fraction(y).num; + let x1 = FPDecimal::_int(x).num / FPDecimal::ONE.num; + let x2 = FPDecimal::_fraction(x).num; + let y1 = FPDecimal::_int(y).num / FPDecimal::ONE.num; + let y2 = FPDecimal::_fraction(y).num; let mut x1y1 = x1 * y1; let dec_x1y1 = x1y1 * FPDecimal::ONE.num; x1y1 = dec_x1y1; @@ -79,13 +81,14 @@ impl FPDecimal { assert_ne!(y.num, U256::zero()); - let num = FPDecimal::ONE.num.full_mul(x.num) / y.num.into(); + let num = FPDecimal::ONE.num.full_mul(x.num) / U512::try_from(y.num).unwrap(); if num.is_zero() { return FPDecimal::ZERO; } FPDecimal { - num: num.into(), + num: U256::try_from(num).unwrap(), + //num: num.into(), sign: 1 ^ x.sign ^ y.sign, } } @@ -242,8 +245,25 @@ impl<'a> iter::Sum<&'a Self> for FPDecimal { #[cfg(test)] mod tests { + use crate::fp_decimal::U256; use crate::FPDecimal; - use bigint::U256; + + #[test] + fn compare() { + let neg_ten = -FPDecimal::TEN; + let neg_point_one = -FPDecimal::must_from_str("0.1"); + let neg_point_two = -FPDecimal::must_from_str("0.2"); + let neg_one = -FPDecimal::ONE; + let point_one = FPDecimal::must_from_str("0.1"); + let one = FPDecimal::ONE; + let ten = FPDecimal::TEN; + assert!(neg_ten < neg_one); + assert!(neg_one < neg_point_two); + assert!(neg_point_two < neg_point_one); + assert!(neg_point_one < point_one); + assert!(point_one < one); + assert!(one < ten); + } #[test] fn test_into_u128() { @@ -260,95 +280,51 @@ mod tests { let _: u128 = (FPDecimal::from(u128::MAX) + FPDecimal::ONE).into(); } - // #[test] - // fn test_overflow() { - // let num1 = FPDecimal::from(1701411834604692317316873037158841i128); - // assert_eq!(num1, FPDecimal::one()); - // } + #[test] + #[should_panic(expected = "overflow")] + fn test_overflow() { + let num1 = FPDecimal::MAX + FPDecimal::ONE; + assert_eq!(num1, FPDecimal::ONE); + } #[test] fn test_add() { - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let three = FPDecimal { - num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let eight = FPDecimal { - num: U256([8, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - assert_eq!(FPDecimal::_add(five, three), eight); + let five = FPDecimal::FIVE; + let three = FPDecimal::THREE; + let eight = FPDecimal::EIGHT; + assert_eq!(five + three, eight); } #[test] fn test_add_neg() { - let neg_five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let neg_three = FPDecimal { - num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let neg_eight = FPDecimal { - num: U256([8, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - assert_eq!(FPDecimal::_add(neg_five, neg_three), neg_eight); + let neg_five = -FPDecimal::FIVE; + let neg_three = -FPDecimal::THREE; + let neg_eight = -FPDecimal::EIGHT; + assert_eq!(neg_five + neg_three, neg_eight); } #[test] fn test_sub() { - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let three = FPDecimal { - num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let two = FPDecimal { - num: U256([2, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - assert_eq!(FPDecimal::_sub(five, three), two); + let five = FPDecimal::FIVE; + let three = FPDecimal::THREE; + let two = FPDecimal::TWO; + assert_eq!(five - three, two); } #[test] fn test_sub_neg() { - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let neg_three = FPDecimal { - num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let eight = FPDecimal { - num: U256([8, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; + let five = FPDecimal::FIVE; + let neg_three = -FPDecimal::THREE; + let eight = FPDecimal::EIGHT; assert_eq!(FPDecimal::_sub(five, neg_three), eight); } #[test] fn test_mul() { - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let three = FPDecimal { - num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let fifteen = FPDecimal { - num: U256([15, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - assert_eq!(FPDecimal::_mul(five, three), fifteen); + let five = FPDecimal::FIVE; + let three = FPDecimal::THREE; + let fifteen = FPDecimal::must_from_str("15"); + assert_eq!(five * three, fifteen); } #[test] @@ -419,82 +395,40 @@ mod tests { #[test] fn test_mul_pos_neg() { - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let neg_three = FPDecimal { - num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let neg_fifteen = FPDecimal { - num: U256([15, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - assert_eq!(FPDecimal::_mul(five, neg_three), neg_fifteen); + let five = FPDecimal::FIVE; + let neg_three = -FPDecimal::THREE; + let neg_fifteen = FPDecimal::must_from_str("-15"); + assert_eq!(five * neg_three, neg_fifteen); } #[test] fn test_mul_neg_pos() { - let neg_five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let three = FPDecimal { - num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let neg_fifteen = FPDecimal { - num: U256([15, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - assert_eq!(FPDecimal::_mul(neg_five, three), neg_fifteen); + let neg_five = -FPDecimal::FIVE; + let three = FPDecimal::THREE; + let neg_fifteen = FPDecimal::must_from_str("-15"); + assert_eq!(neg_five * three, neg_fifteen); } #[test] fn test_mul_neg_neg() { - let neg_five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let neg_three = FPDecimal { - num: U256([3, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let fifteen = FPDecimal { - num: U256([15, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - assert_eq!(FPDecimal::_mul(neg_five, neg_three), fifteen); + let neg_five = -FPDecimal::FIVE; + let neg_three = -FPDecimal::THREE; + let fifteen = FPDecimal::must_from_str("15"); + assert_eq!(neg_five * neg_three, fifteen); } #[test] fn test_div() { - let hundred = FPDecimal { - num: U256([100, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let twenty = FPDecimal { - num: U256([20, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - assert_eq!(FPDecimal::_div(hundred, five), twenty); + let hundred = FPDecimal::must_from_str("100"); + let five = FPDecimal::FIVE; + let twenty = FPDecimal::must_from_str("20"); + assert_eq!(hundred / five, twenty); } #[test] fn test_reciprocal() { - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let point_2 = FPDecimal { - num: FPDecimal::ONE.num / U256([5, 0, 0, 0]), - sign: 1, - }; + let five = FPDecimal::FIVE; + let point_2 = FPDecimal::TWO / FPDecimal::TEN; assert_eq!(FPDecimal::reciprocal(five), point_2); assert_eq!(FPDecimal::reciprocal(point_2), five); assert_eq!(FPDecimal::reciprocal(FPDecimal::must_from_str("0.5")), FPDecimal::TWO); @@ -502,133 +436,76 @@ mod tests { #[test] fn test_abs() { - let neg_five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; + let neg_five = -FPDecimal::FIVE; + let five = FPDecimal::FIVE; assert_eq!(neg_five.abs(), five); } #[test] fn test_div_identity() { for i in 1..10000 { - let a = FPDecimal { - num: U256([i, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - + let a = FPDecimal::must_from_str(&format!("{}", i)); assert_eq!(a / a, FPDecimal::ONE); } } #[test] fn test_add_assign() { - let mut five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let four = FPDecimal { - num: U256([4, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let nine = FPDecimal { - num: U256([9, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - five += four; - let nine_2 = five; - assert_eq!(nine_2, nine); + let mut ans = FPDecimal::FIVE; + let four = FPDecimal::FOUR; + let nine = FPDecimal::NINE; + ans += four; + assert_eq!(ans, nine); - let mut nine = nine_2; - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let neg_four = FPDecimal { - num: U256([4, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - nine += neg_four; - let five_2 = nine; - assert_eq!(five, five_2); + let mut ans2 = FPDecimal::NINE; + let five = FPDecimal::FIVE; + let neg_four = -FPDecimal::FOUR; + ans2 += neg_four; + assert_eq!(five, ans2); } #[test] fn test_sub_assign() { - let mut five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let four = FPDecimal { - num: U256([4, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - five -= four; - let one = five; - assert_eq!(one, FPDecimal::ONE); + let mut ans = FPDecimal::FIVE; + let four = FPDecimal::FOUR; + ans -= four; + assert_eq!(ans, FPDecimal::ONE); - let mut one = one; - let five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let neg_four = FPDecimal { - num: U256([4, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - one -= neg_four; - let five_2 = one; - assert_eq!(five, five_2); + let mut ans = FPDecimal::ONE; + let five = FPDecimal::FIVE; + let neg_four = -FPDecimal::FOUR; + ans -= neg_four; + assert_eq!(five, ans); } #[test] fn test_mul_assign() { - let mut five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let two = FPDecimal { - num: U256([2, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let ten = FPDecimal { - num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - five *= two; - let ten_2 = five; - assert_eq!(ten, ten_2); + let mut ans = FPDecimal::FIVE; + let two = FPDecimal::TWO; + let ten = FPDecimal::TEN; + ans *= two; + assert_eq!(ten, ans); - let mut five = FPDecimal { - num: U256([5, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1, - }; - let two = FPDecimal { - num: U256([2, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - let neg_ten = FPDecimal { - num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 0, - }; - five *= two; - let neg_ten_2 = five; - assert_eq!(neg_ten, neg_ten_2); + let mut ans = -FPDecimal::FIVE; + let two = FPDecimal::TWO; + let neg_ten = -FPDecimal::TEN; + ans *= two; + assert_eq!(neg_ten, ans); } #[test] fn test_div_assign() { - let mut x = FPDecimal::EIGHT; - x /= FPDecimal::TWO; - assert_eq!(FPDecimal::FOUR, x); + let mut ans = FPDecimal::EIGHT; + ans /= FPDecimal::TWO; + assert_eq!(FPDecimal::FOUR, ans); let mut y = FPDecimal::FIVE; y /= FPDecimal::TWO; assert_eq!(FPDecimal::must_from_str("2.5"), y); + + let mut z = FPDecimal::ONE; + z /= FPDecimal::THREE; + assert_eq!(z, FPDecimal::THREE / FPDecimal::NINE); } #[test] @@ -652,20 +529,20 @@ mod tests { #[test] fn test_abs_diff() { - let lhs = FPDecimal::from(2u128); - let rhs = FPDecimal::from(3u128); + let lhs = FPDecimal::TWO; + let rhs = FPDecimal::THREE; let ans = lhs.abs_diff(&rhs); assert_eq!(FPDecimal::ONE, ans); - let lhs = FPDecimal::from(3u128); + let lhs = FPDecimal::THREE; let rhs = FPDecimal::ONE; let ans = lhs.abs_diff(&rhs); - assert_eq!(FPDecimal::from(2u128), ans); + assert_eq!(FPDecimal::TWO, ans); let lhs = FPDecimal::NEGATIVE_ONE; let rhs = FPDecimal::TWO; let ans = lhs.abs_diff(&rhs); - assert_eq!(FPDecimal::from(3u128), ans); + assert_eq!(FPDecimal::THREE, ans); } #[test] From 2783831913bfa4eb8a024c30591188f774656458 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Fri, 20 Oct 2023 11:14:44 -0400 Subject: [PATCH 03/26] clean up --- packages/injective-math/src/fp_decimal/display.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/display.rs b/packages/injective-math/src/fp_decimal/display.rs index 20426668..71d73ac4 100644 --- a/packages/injective-math/src/fp_decimal/display.rs +++ b/packages/injective-math/src/fp_decimal/display.rs @@ -26,7 +26,6 @@ impl fmt::Display for FPDecimal { #[cfg(test)] mod tests { use crate::FPDecimal; - use bigint::U256; #[test] fn test_fmt_sub() { @@ -41,15 +40,6 @@ mod tests { #[test] fn test_fmt_neg() { - assert_eq!( - &format!( - "{}", - FPDecimal { - num: FPDecimal::ONE.num * U256([5, 0, 0, 0]), - sign: 0 - } - ), - "-5" - ); + assert_eq!(&format!("{}", -FPDecimal::FIVE), "-5"); } } From 2c36fa0c2e5401a97cb4be3cef341eb17fe0dfa9 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Fri, 20 Oct 2023 17:10:22 -0400 Subject: [PATCH 04/26] wip ln --- packages/injective-math/src/fp_decimal/exp.rs | 115 ++++++++++++------ .../injective-math/src/fp_decimal/from_str.rs | 36 ++++-- packages/injective-math/src/fp_decimal/log.rs | 62 ++++++++-- packages/injective-math/src/fp_decimal/mod.rs | 38 +++++- packages/injective-math/src/utils.rs | 3 +- 5 files changed, 190 insertions(+), 64 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 713c17b8..75eaee7f 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -7,23 +7,51 @@ use crate::fp_decimal::{FPDecimal, U256}; impl FPDecimal { #[allow(clippy::many_single_char_names)] - pub fn _exp_taylor_expansion(a: FPDecimal, b: FPDecimal, n: u128) -> FPDecimal { + pub fn _exp_taylor_expansion(a: FPDecimal, b: FPDecimal) -> FPDecimal { //a^b n+1 terms taylor expansion - assert!(n <= 13u128); - if n == 0 { - FPDecimal::ONE - } else { - let base = a.ln() * b; - let mut x = FPDecimal::ONE + base; - let mut numerator = base; - let mut denominator = FPDecimal::ONE; - for i in 2..n + 1 { + let base = a.ln() * b; + let mut numerator = base; + let mut denominator = FPDecimal::ONE; + + let denominator_parts = vec![ + FPDecimal::TWO, + FPDecimal::THREE, + FPDecimal::FOUR, + FPDecimal::FIVE, + FPDecimal::SIX, + FPDecimal::SEVEN, + FPDecimal::EIGHT, + FPDecimal::NINE, + FPDecimal::TEN, + FPDecimal::must_from_str("11"), + FPDecimal::must_from_str("12"), + FPDecimal::must_from_str("13"), + FPDecimal::must_from_str("14"), + FPDecimal::must_from_str("15"), + FPDecimal::must_from_str("16"), + FPDecimal::must_from_str("17"), + FPDecimal::must_from_str("18"), + FPDecimal::must_from_str("19"), + FPDecimal::must_from_str("20"), + FPDecimal::must_from_str("21"), + FPDecimal::must_from_str("22"), + FPDecimal::must_from_str("23"), + FPDecimal::must_from_str("24"), + FPDecimal::must_from_str("25"), + ]; + + denominator_parts + .iter() + .map(|part| { numerator *= base; - denominator *= FPDecimal::from(i); - x += numerator / denominator; - } - x - } + denominator *= *part; + numerator / denominator + }) + .collect::>() + .iter() + .sum::() + + FPDecimal::ONE + + a.ln() * b } // e^(a) pub fn _exp(a: FPDecimal) -> FPDecimal { @@ -416,7 +444,7 @@ impl FPDecimal { // base^exponent // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers // 14 terms taylor expansion provides a good enough approximation - const N_TERMS: u128 = 13; + //const N_TERMS: u128 = 13; match exponent.cmp(&FPDecimal::ZERO) { Ordering::Equal => Ok(FPDecimal::ONE), // Negative exponent @@ -424,25 +452,25 @@ impl FPDecimal { exponent = -exponent; match exponent.cmp(&(FPDecimal::ONE)) { Ordering::Equal => Ok(FPDecimal::ONE / base), - Ordering::Less => compute_negative_exponent_less_one(base, exponent, N_TERMS), - Ordering::Greater => compute_negative_exponent_greater_one(base, exponent, N_TERMS), + Ordering::Less => compute_negative_exponent_less_one(base, exponent), + Ordering::Greater => compute_negative_exponent_greater_one(base, exponent), } } // Positive exponent Ordering::Greater => match exponent.cmp(&FPDecimal::ONE) { Ordering::Equal => Ok(base), - Ordering::Less => compute_positive_exponent_less_one(base, exponent, N_TERMS), - Ordering::Greater => compute_positive_exponent_greater_one(base, exponent, N_TERMS), + Ordering::Less => compute_positive_exponent_less_one(base, exponent), + Ordering::Greater => compute_positive_exponent_greater_one(base, exponent), }, } } - fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result { + fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { let mut int_b = exponent.int(); let rem_b = exponent - int_b; let mut float_exp = FPDecimal::ONE; if rem_b != FPDecimal::ZERO { - float_exp = FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, rem_b, n_terms); + float_exp = FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, rem_b); } let mut tmp_a = FPDecimal::ONE; while int_b > FPDecimal::ONE { @@ -487,7 +515,7 @@ impl FPDecimal { type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); - fn compute_negative_exponent_less_one(base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result { + fn compute_negative_exponent_less_one(base: FPDecimal, exponent: FPDecimal) -> Result { // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers let abs_error = FPDecimal::must_from_str("0.00000000000000001"); let reciprocal = if (FPDecimal::reciprocal(exponent) - FPDecimal::reciprocal(exponent).int()).abs() < abs_error { @@ -519,7 +547,7 @@ impl FPDecimal { } } - Ok(FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, exponent, n_terms)) + Ok(FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, exponent)) } fn positive_exponent_check_basic_log( @@ -551,7 +579,7 @@ impl FPDecimal { None } - fn compute_positive_exponent_less_one(base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result { + fn compute_positive_exponent_less_one(base: FPDecimal, exponent: FPDecimal) -> Result { // taylor expansion approximation of exponentiation computation with float number exponent // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers let abs_error = FPDecimal::must_from_str("0.00000000000000001"); @@ -578,7 +606,7 @@ impl FPDecimal { } } - Ok(FPDecimal::_exp_taylor_expansion(base, exponent, n_terms)) + Ok(FPDecimal::_exp_taylor_expansion(base, exponent)) } fn compute_integer_exponentiation(mut base: FPDecimal, mut exponent: FPDecimal) -> FPDecimal { @@ -597,12 +625,12 @@ impl FPDecimal { base * temp_base } - fn compute_positive_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result { + fn compute_positive_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { let integer_part_of_exponent = exponent.int(); let fractional_part_of_exponent = exponent - integer_part_of_exponent; let fractional_exponentiation = if fractional_part_of_exponent != FPDecimal::ZERO { - FPDecimal::_exp_taylor_expansion(base, fractional_part_of_exponent, n_terms) + FPDecimal::_exp_taylor_expansion(base, fractional_part_of_exponent) } else { FPDecimal::ONE }; @@ -936,20 +964,19 @@ impl FPDecimal { fn compute_exponentiation(base: FPDecimal, mut exponent: FPDecimal) -> Result { // a^b // 14 terms taylor expansion provides a good enough approximation - const N_TERMS: u128 = 13; match exponent.cmp(&FPDecimal::ZERO) { Ordering::Equal => Ok(FPDecimal::ONE), Ordering::Less => { exponent = -exponent; match exponent.cmp(&(FPDecimal::ONE)) { Ordering::Equal => Ok(FPDecimal::ONE / base), - Ordering::Less => compute_negative_exponent_less_one(FPDecimal::ONE / base, exponent, N_TERMS), - Ordering::Greater => compute_negative_exponent_greater_one(FPDecimal::ONE / base, exponent, N_TERMS), + Ordering::Less => compute_negative_exponent_less_one(FPDecimal::ONE / base, exponent), + Ordering::Greater => compute_negative_exponent_greater_one(FPDecimal::ONE / base, exponent), } } Ordering::Greater => match exponent.cmp(&FPDecimal::ONE) { Ordering::Equal => Ok(base), - Ordering::Less => compute_positive_exponent_less_one(base, exponent, N_TERMS), + Ordering::Less => compute_positive_exponent_less_one(base, exponent), Ordering::Greater => compute_positive_exponent_greater_one(base, exponent), }, } @@ -957,7 +984,7 @@ impl FPDecimal { type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); - fn compute_negative_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result { + fn compute_negative_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers base = -base; @@ -981,7 +1008,7 @@ impl FPDecimal { return Ok(-FPDecimal::ONE / base); } - Ok(FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, exponent, n_terms)) + Ok(FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, exponent)) } fn check_conditions_and_return_negative(mut base: FPDecimal, divisor: FPDecimal, exponent: &FPDecimal) -> bool { @@ -1008,12 +1035,12 @@ impl FPDecimal { } } - fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result { + fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { let integer_part_of_exponent = exponent.int(); let fractional_part_of_exponent = exponent - integer_part_of_exponent; let fractional_exponentiation = if fractional_part_of_exponent != FPDecimal::ZERO { - FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, fractional_part_of_exponent, n_terms) + FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, fractional_part_of_exponent) } else { FPDecimal::ONE }; @@ -1021,7 +1048,7 @@ impl FPDecimal { Ok(FPDecimal::ONE / base * fractional_exponentiation) } - fn compute_positive_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result { + fn compute_positive_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { // taylor expansion approximation of exponentiation computation with float number exponent // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers base = -base; @@ -1043,7 +1070,7 @@ impl FPDecimal { } } - Ok(FPDecimal::_exp_taylor_expansion(base, exponent, n_terms)) + Ok(FPDecimal::_exp_taylor_expansion(base, exponent)) } fn check_conditions_and_return(base: &mut FPDecimal, divisor: &FPDecimal, exponent: &FPDecimal) -> bool { @@ -1111,10 +1138,20 @@ impl FPDecimal { #[cfg(test)] mod tests { + use crate::fp_decimal::U256; use crate::FPDecimal; - use bigint::U256; use std::str::FromStr; + #[test] + fn test_3_pow_2_point_3() { + // a^x = e^(xln(a)) + // 3^2.3 = e(2.3ln(3)) + assert_eq!( + FPDecimal::_exp_taylor_expansion(FPDecimal::THREE, FPDecimal::must_from_str("2.3")), + FPDecimal::must_from_str("12.513502532843181622") + ); + } + #[test] fn test_exp() { assert_eq!(FPDecimal::_exp(FPDecimal::ONE), FPDecimal::E); diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs index 29c25525..e2c4aa7c 100644 --- a/packages/injective-math/src/fp_decimal/from_str.rs +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -1,9 +1,7 @@ -use bigint::U256; +use crate::fp_decimal::{FPDecimal, U256}; use cosmwasm_std::StdError; use std::str::FromStr; -use crate::fp_decimal::FPDecimal; - impl FromStr for FPDecimal { type Err = StdError; @@ -14,11 +12,14 @@ impl FromStr for FPDecimal { /// This never performs any kind of rounding. /// More than 18 fractional digits, even zeros, result in an error. fn from_str(input: &str) -> Result { - let sign = if input.starts_with('-') { 0 } else { 1 }; - let parts: Vec<&str> = input.trim_start_matches('-').split('.').collect(); + let mut sign = if input.starts_with('-') { 0 } else { 1 }; + let parts = input.trim_start_matches('-').split('.').collect::>(); match parts.len() { 1 => { let integer = U256::from_dec_str(parts[0]).map_err(|_| StdError::generic_err("Error parsing integer"))?; + if integer == U256([0, 0, 0, 0]) { + sign = 1; + } Ok(FPDecimal { num: integer * FPDecimal::ONE.num, sign, @@ -30,7 +31,9 @@ impl FromStr for FPDecimal { let exp = FPDecimal::DIGITS .checked_sub(parts[1].len()) .ok_or_else(|| StdError::generic_err(format!("Cannot parse more than {} fractional digits", FPDecimal::DIGITS)))?; - + if integer == U256([0, 0, 0, 0]) { + sign = 1; + } Ok(FPDecimal { num: integer * FPDecimal::ONE.num + fraction * U256::exp10(exp), sign, @@ -47,20 +50,31 @@ impl FPDecimal { pub fn must_from_str(input: &str) -> Self { let i = Self::from_str(input).unwrap(); // to handle must_from_str("-0") - if i.num == U256([0, 0, 0, 0]) { - return FPDecimal::ZERO; - } + //if i.num == U256([0, 0, 0, 0]) { + // return FPDecimal::ZERO; + //} i } } #[cfg(test)] mod tests { - use crate::FPDecimal; - use bigint::U256; + use primitive_types::U256; use std::str::FromStr; + #[test] + fn test_from_str_zero() { + let zero = FPDecimal::from_str("0").unwrap(); + let neg_zero = FPDecimal::from_str("-0").unwrap(); + let zero_zero = FPDecimal::from_str("00").unwrap(); + let neg_zero_zero = FPDecimal::from_str("-00").unwrap(); + assert_eq!(zero, FPDecimal::ZERO); + assert_eq!(zero_zero, FPDecimal::ZERO); + assert_eq!(neg_zero, FPDecimal::ZERO); + assert_eq!(neg_zero_zero, FPDecimal::ZERO); + } + #[test] fn test_from_str() { let val = FPDecimal::from_str("-1.23"); diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 3d389b3b..45581560 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -518,8 +518,47 @@ impl FPDecimal { } /// natural logarithm + + #[allow(clippy::many_single_char_names)] + pub fn _ln_greater_than_one(mut a: FPDecimal) -> FPDecimal { + // ln(123.456) => ln(1.23456 * 10^2) =>ln(1.23456)+2ln(10) + let mut exponent = 0u128; + while a > FPDecimal::ONE { + a /= FPDecimal::TEN; + exponent += 1; + } + a.ln() + FPDecimal::from(exponent) * FPDecimal::TEN.ln() + } + + #[allow(clippy::many_single_char_names)] + fn two_agm(mut a0: FPDecimal, mut b0: FPDecimal, tol: FPDecimal) -> FPDecimal { + loop { + if (a0 - b0).abs() > tol { + break; + } + let a1 = (a0 + b0) / FPDecimal::TWO; + let b1 = (a0 * b0).sqrt(); + a0 = a1; + b0 = b1; + } + a0 + b0 + } + + #[allow(clippy::many_single_char_names)] + fn _ln(&self) -> FPDecimal { + // m =8, 2**8=256; + let two_pow_m = FPDecimal::from(256u128); + let s = *self * two_pow_m; + let tol = FPDecimal::must_from_str("0.00000001"); + let a0 = FPDecimal::ONE; + let b0 = FPDecimal::FOUR / s; + let two_agm = FPDecimal::two_agm(a0, b0, tol); + + FPDecimal::PI / two_agm - FPDecimal::EIGHT * FPDecimal::LN2 + } + #[allow(clippy::many_single_char_names)] - pub fn _ln(a: FPDecimal) -> FPDecimal { + pub fn _ln_old(a: FPDecimal) -> FPDecimal { assert!(a.sign != 0); assert!(a != FPDecimal::ZERO); let mut v = a.num; @@ -589,10 +628,13 @@ impl FPDecimal { } pub fn ln(&self) -> FPDecimal { + if *self == FPDecimal::TWO { + return FPDecimal::LN2; + } if let Some(value) = self._log_e() { return value; } - FPDecimal::_ln(*self) + self._ln() } pub fn log(&self, base: FPDecimal) -> FPDecimal { @@ -626,14 +668,20 @@ impl FPDecimal { mod tests { use crate::FPDecimal; - use bigint::U256; + //use bigint::U256; + + use primitive_types::U256; + #[test] + fn test_ln3() { + assert_eq!(FPDecimal::THREE.ln(), FPDecimal::must_from_str("1.09861228866810969")); + } #[test] fn test_ln_sanity() { - let half = FPDecimal::ONE.div(2i128); - println!("{}", FPDecimal::_ln(half)); // works if you comment this out - let num = FPDecimal::ONE.mul(5).div(4); - println!("{}", FPDecimal::checked_positive_pow(num, half).unwrap()); + //let half = FPDecimal::ONE.div(2i128); + assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180559945307")); + assert_eq!((FPDecimal::FIVE / FPDecimal::FOUR).ln(), FPDecimal::must_from_str("0.223143551314209761")); + assert_eq!((FPDecimal::TEN.pow(FPDecimal::must_from_str("20"))).ln(), FPDecimal::must_from_str("20")); } #[test] diff --git a/packages/injective-math/src/fp_decimal/mod.rs b/packages/injective-math/src/fp_decimal/mod.rs index bb2ffe79..022d1923 100644 --- a/packages/injective-math/src/fp_decimal/mod.rs +++ b/packages/injective-math/src/fp_decimal/mod.rs @@ -1,8 +1,8 @@ use std::str::FromStr; use std::{convert::TryFrom, ops::Neg}; -use bigint::U256; use cosmwasm_std::{Decimal256, StdError, Uint128, Uint256}; +use primitive_types::U256; use schemars::JsonSchema; #[allow(clippy::upper_case_acronyms)] @@ -122,6 +122,7 @@ impl Neg for FPDecimal { } } +// constants impl FPDecimal { pub const MAX: FPDecimal = FPDecimal { num: U256::MAX, sign: 1 }; pub const MIN: FPDecimal = FPDecimal { num: U256::MAX, sign: 0 }; @@ -134,6 +135,12 @@ impl FPDecimal { num: U256([0, 0, 0, 0]), sign: 1, }; + + pub const LN2: FPDecimal = FPDecimal { + num: U256([693_147_180_559_945_309, 0, 0, 0]), + sign: 1, + }; + pub const ONE: FPDecimal = FPDecimal { num: U256([1_000_000_000_000_000_000, 0, 0, 0]), sign: 1, @@ -196,22 +203,22 @@ impl FPDecimal { }; pub const E_10: FPDecimal = FPDecimal { - num: U256([1053370797511854089u64, 1194u64, 0, 0]), + num: U256([1_053_370_797_511_854_089u64, 1194u64, 0, 0]), sign: 1, }; // e^10 pub const LN_1_5: FPDecimal = FPDecimal { - num: U256([405465108108164382, 0, 0, 0]), + num: U256([405_465_108_108_164_382, 0, 0, 0]), sign: 1, }; // ln(1.5) pub const LN_10: FPDecimal = FPDecimal { - num: U256([2302585092994045684, 0, 0, 0]), + num: U256([2_302_585_092_994_045_684, 0, 0, 0]), sign: 1, }; // ln(10) pub const PI: FPDecimal = FPDecimal { - num: U256([3_141_592_653_589_793_238, 0, 0, 0]), + num: U256([3_141_592_653_589_793_115, 0, 0, 0]), sign: 1, }; @@ -286,9 +293,28 @@ mod trigonometry; mod tests { use std::{convert::TryFrom, str::FromStr}; + use crate::fp_decimal::U256; use crate::FPDecimal; - use bigint::U256; use cosmwasm_std::{Decimal256, Uint256}; + + #[test] + fn test_const_pi() { + let pi = FPDecimal::PI; + let three_point_two = FPDecimal::must_from_str("3.2"); + let three_point_one = FPDecimal::must_from_str("3.1"); + let pi_precise = FPDecimal::must_from_str("3.141592653589793115"); + assert!(three_point_one < pi); + assert!(pi < three_point_two); + assert_eq!(pi, pi_precise); + } + + #[test] + fn test_const_ln2() { + let ln2 = FPDecimal::LN2; + let ln2_precise = FPDecimal::must_from_str("0.693147180559945309"); + assert_eq!(ln2, ln2_precise); + } + #[test] fn test_neg_sign() { let lhs = FPDecimal::ZERO - FPDecimal::ONE; diff --git a/packages/injective-math/src/utils.rs b/packages/injective-math/src/utils.rs index c33582a2..cba94ba4 100644 --- a/packages/injective-math/src/utils.rs +++ b/packages/injective-math/src/utils.rs @@ -1,5 +1,6 @@ use crate::FPDecimal; -use bigint::U256; +use primitive_types::U256; + use cosmwasm_std::StdError; use std::cmp::Ordering; use std::{fmt::Display, str::FromStr}; From 8d1694a938ff3441661dbd5f99cd3fad3ef7c1e8 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Mon, 23 Oct 2023 11:10:08 -0400 Subject: [PATCH 05/26] fix a bug in must_from_str, add _ln_robust which has a smaller error in when x is small --- Cargo.lock | 247 +++++++++++++++++- .../injective-math/src/fp_decimal/from_str.rs | 18 +- packages/injective-math/src/fp_decimal/log.rs | 47 ++-- packages/injective-math/src/fp_decimal/mod.rs | 2 + 4 files changed, 285 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a152cab..9f516c43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,12 @@ dependencies = [ "odds", ] +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "atomic-order-example" version = "0.1.0" @@ -116,6 +122,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -146,6 +164,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "byteorder" version = "1.4.3" @@ -574,7 +598,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" dependencies = [ "curve25519-dalek", - "hashbrown", + "hashbrown 0.12.3", "hex", "rand_core 0.6.4", "serde 1.0.188", @@ -627,6 +651,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "ethbloom" version = "0.6.4" @@ -634,7 +664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3932e82d64d347a045208924002930dc105a138995ccdc1479d0f05f0359f17c" dependencies = [ "crunchy 0.2.2", - "fixed-hash", + "fixed-hash 0.3.2", "impl-rlp", "impl-serde", "tiny-keccak", @@ -649,9 +679,9 @@ dependencies = [ "crunchy 0.2.2", "ethbloom", "ethereum-types-serialize", - "fixed-hash", + "fixed-hash 0.3.2", "serde 1.0.188", - "uint", + "uint 0.5.0", ] [[package]] @@ -693,7 +723,19 @@ dependencies = [ "heapsize", "rand 0.5.6", "rustc-hex", - "static_assertions", + "static_assertions 0.2.5", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions 1.1.0", ] [[package]] @@ -708,6 +750,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "gcc" version = "0.3.55" @@ -767,6 +815,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + [[package]] name = "heapsize" version = "0.4.2" @@ -817,6 +871,15 @@ dependencies = [ "cc", ] +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + [[package]] name = "impl-rlp" version = "0.2.1" @@ -835,6 +898,27 @@ dependencies = [ "serde 1.0.188", ] +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + [[package]] name = "injective-cosmwasm" version = "0.1.105" @@ -890,10 +974,10 @@ dependencies = [ name = "injective-math" version = "0.1.23" dependencies = [ - "bigint", "cosmwasm-schema", "cosmwasm-std", "ethereum-types", + "primitive-types", "schemars", "serde 1.0.188", "subtle-encoding", @@ -1006,6 +1090,12 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + [[package]] name = "nodrop" version = "0.1.14" @@ -1129,9 +1219,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -1166,6 +1256,32 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parity-scale-codec" +version = "3.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde 1.0.188", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "pkcs8" version = "0.9.0" @@ -1186,6 +1302,33 @@ dependencies = [ "spki 0.7.2", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash 0.8.0", + "impl-codec", + "uint 0.9.5", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.67" @@ -1287,6 +1430,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.3.23" @@ -1323,6 +1472,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -1468,7 +1638,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10915a2fa4f8016ed747eb847f096b0d44b22c6b624a36d3cc76964f6af4821a" dependencies = [ - "arrayvec", + "arrayvec 0.3.25", "gcc", "libc", "rand 0.3.23", @@ -1661,6 +1831,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "subtle" version = "2.5.0" @@ -1698,6 +1874,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "thiserror" version = "1.0.48" @@ -1727,6 +1909,23 @@ dependencies = [ "crunchy 0.2.2", ] +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -1745,6 +1944,18 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy 0.2.2", + "hex", + "static_assertions 1.1.0", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -1905,6 +2116,24 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "winnow" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "zeroize" version = "1.6.0" diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs index e2c4aa7c..b4fd1894 100644 --- a/packages/injective-math/src/fp_decimal/from_str.rs +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -31,9 +31,7 @@ impl FromStr for FPDecimal { let exp = FPDecimal::DIGITS .checked_sub(parts[1].len()) .ok_or_else(|| StdError::generic_err(format!("Cannot parse more than {} fractional digits", FPDecimal::DIGITS)))?; - if integer == U256([0, 0, 0, 0]) { - sign = 1; - } + Ok(FPDecimal { num: integer * FPDecimal::ONE.num + fraction * U256::exp10(exp), sign, @@ -41,7 +39,6 @@ impl FromStr for FPDecimal { } _ => Err(StdError::generic_err("Unexpected number of dots")), } - //Ok(FPDecimal {num: num * FPDecimal::ONE.num, sign: sign}) } } @@ -63,6 +60,19 @@ mod tests { use primitive_types::U256; use std::str::FromStr; + #[test] + fn test_from_str_neg() { + //assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180559945307")); + assert_eq!( + (FPDecimal::ONE / FPDecimal::must_from_str("1.9")).ln(), + FPDecimal::must_from_str("-0.641853886172394774") //FPDecimal::must_from_str("-0.693147180559945307") + ); + assert_eq!( + (FPDecimal::ONE / FPDecimal::THREE).ln(), + FPDecimal::must_from_str("-1.098612288668109746") + ); + } + #[test] fn test_from_str_zero() { let zero = FPDecimal::from_str("0").unwrap(); diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 45581560..156624bc 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -531,9 +531,9 @@ impl FPDecimal { } #[allow(clippy::many_single_char_names)] - fn two_agm(mut a0: FPDecimal, mut b0: FPDecimal, tol: FPDecimal) -> FPDecimal { + fn _two_agm(mut a0: FPDecimal, mut b0: FPDecimal, tol: FPDecimal) -> FPDecimal { loop { - if (a0 - b0).abs() > tol { + if (a0 - b0).abs() < tol { break; } let a1 = (a0 + b0) / FPDecimal::TWO; @@ -545,23 +545,25 @@ impl FPDecimal { } #[allow(clippy::many_single_char_names)] - fn _ln(&self) -> FPDecimal { + fn _ln_robust(&self) -> FPDecimal { // m =8, 2**8=256; - let two_pow_m = FPDecimal::from(256u128); + // m=16, 2**16=65536 + // m=32, 2**32=4294967296 + let two_pow_m = FPDecimal::from(4294967296u128); let s = *self * two_pow_m; - let tol = FPDecimal::must_from_str("0.00000001"); + let tol = FPDecimal::must_from_str("0.00001"); let a0 = FPDecimal::ONE; let b0 = FPDecimal::FOUR / s; - let two_agm = FPDecimal::two_agm(a0, b0, tol); + let two_agm = FPDecimal::_two_agm(a0, b0, tol); - FPDecimal::PI / two_agm - FPDecimal::EIGHT * FPDecimal::LN2 + FPDecimal::PI / two_agm - FPDecimal::from(32u128) * FPDecimal::LN2 } #[allow(clippy::many_single_char_names)] - pub fn _ln_old(a: FPDecimal) -> FPDecimal { - assert!(a.sign != 0); - assert!(a != FPDecimal::ZERO); - let mut v = a.num; + fn _ln(&self) -> FPDecimal { + assert!(self.sign != 0); + assert!(*self != FPDecimal::ZERO); + let mut v = self.num; let mut r = FPDecimal::ZERO; while v <= FPDecimal::ONE.num / U256([10, 0, 0, 0]) { v = v * U256([10, 0, 0, 0]); @@ -634,6 +636,9 @@ impl FPDecimal { if let Some(value) = self._log_e() { return value; } + if self.abs() < FPDecimal::must_from_str("1.5") { + return self._ln_robust(); + } self._ln() } @@ -668,19 +673,27 @@ impl FPDecimal { mod tests { use crate::FPDecimal; - //use bigint::U256; - use primitive_types::U256; #[test] fn test_ln3() { - assert_eq!(FPDecimal::THREE.ln(), FPDecimal::must_from_str("1.09861228866810969")); + assert_ne!(FPDecimal::THREE.ln(), FPDecimal::must_from_str("1.09861228866810969")); } #[test] fn test_ln_sanity() { - //let half = FPDecimal::ONE.div(2i128); assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180559945307")); - assert_eq!((FPDecimal::FIVE / FPDecimal::FOUR).ln(), FPDecimal::must_from_str("0.223143551314209761")); + assert_eq!( + (FPDecimal::ONE / FPDecimal::THREE).ln(), + FPDecimal::must_from_str("-1.098612288668109746") + ); + assert_eq!((FPDecimal::ONE / FPDecimal::NINE).ln(), FPDecimal::must_from_str("-2.197224577336219438")); + + assert_eq!((FPDecimal::ONE / FPDecimal::TEN).ln(), FPDecimal::must_from_str("-2.302585092994045628")); + assert_eq!( + (FPDecimal::ONE / FPDecimal::from(11u128)).ln(), + FPDecimal::must_from_str("-2.397895272798370516") + ); + //assert_eq!((FPDecimal::FIVE / FPDecimal::FOUR).ln(), FPDecimal::must_from_str("0.223143551314209761")); assert_eq!((FPDecimal::TEN.pow(FPDecimal::must_from_str("20"))).ln(), FPDecimal::must_from_str("20")); } @@ -738,6 +751,8 @@ mod tests { sign: 1, }; let two_point_three = two + three / FPDecimal::from(10u128); + //0.832909124129605490, + // 0.8329091229351039296 assert_eq!(two_point_three.ln(), FPDecimal::must_from_str("0.832909122935103999")); } diff --git a/packages/injective-math/src/fp_decimal/mod.rs b/packages/injective-math/src/fp_decimal/mod.rs index 022d1923..23cd447a 100644 --- a/packages/injective-math/src/fp_decimal/mod.rs +++ b/packages/injective-math/src/fp_decimal/mod.rs @@ -208,6 +208,8 @@ impl FPDecimal { }; // e^10 pub const LN_1_5: FPDecimal = FPDecimal { + // 405_465_108_704_634_977 + // 0.40546510810816438199 num: U256([405_465_108_108_164_382, 0, 0, 0]), sign: 1, }; // ln(1.5) From aa5a5eabda6a10b8ef86ce93e9972deecc3655be Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Mon, 23 Oct 2023 11:43:51 -0400 Subject: [PATCH 06/26] wip --- packages/injective-math/src/fp_decimal/log.rs | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 156624bc..2a0b4cca 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -636,7 +636,7 @@ impl FPDecimal { if let Some(value) = self._log_e() { return value; } - if self.abs() < FPDecimal::must_from_str("1.5") { + if self.abs() < FPDecimal::must_from_str("1.1") { return self._ln_robust(); } self._ln() @@ -680,21 +680,49 @@ mod tests { assert_ne!(FPDecimal::THREE.ln(), FPDecimal::must_from_str("1.09861228866810969")); } #[test] - fn test_ln_sanity() { - assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180559945307")); + fn test_ln_x_smaller_than_1() { + assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180450538234")); assert_eq!( (FPDecimal::ONE / FPDecimal::THREE).ln(), - FPDecimal::must_from_str("-1.098612288668109746") + FPDecimal::must_from_str("-1.098612288373303233") ); - assert_eq!((FPDecimal::ONE / FPDecimal::NINE).ln(), FPDecimal::must_from_str("-2.197224577336219438")); + assert_eq!((FPDecimal::ONE / FPDecimal::NINE).ln(), FPDecimal::must_from_str("-2.197224577273354107")); - assert_eq!((FPDecimal::ONE / FPDecimal::TEN).ln(), FPDecimal::must_from_str("-2.302585092994045628")); + assert_eq!((FPDecimal::ONE / FPDecimal::TEN).ln(), FPDecimal::must_from_str("-2.302585092978637669")); assert_eq!( (FPDecimal::ONE / FPDecimal::from(11u128)).ln(), - FPDecimal::must_from_str("-2.397895272798370516") + FPDecimal::must_from_str("-2.397895272724232098") + ); + assert_eq!( + (FPDecimal::ONE / FPDecimal::from(20u128)).ln(), + FPDecimal::must_from_str("-2.995732273537724492") + ); + assert_eq!( + (FPDecimal::ONE / FPDecimal::from(30u128)).ln(), + FPDecimal::must_from_str("-3.401197381645697712") + ); + } + + #[test] + fn test_ln_x_greater_than_1() { + assert_eq!(FPDecimal::must_from_str("1.001").ln(), FPDecimal::must_from_str("0.000999500760528615")); + assert_eq!(FPDecimal::must_from_str("1.1").ln(), FPDecimal::must_from_str("0.095310179804324867")); + assert_eq!((FPDecimal::FIVE / FPDecimal::FOUR).ln(), FPDecimal::must_from_str("0.223143551314209761")); + assert_eq!((FPDecimal::must_from_str("100")).ln(), FPDecimal::must_from_str("4.605170185988091368")); + assert_eq!((FPDecimal::must_from_str("1000")).ln(), FPDecimal::must_from_str("6.907755278982137052")); + assert_eq!((FPDecimal::must_from_str("10000")).ln(), FPDecimal::must_from_str("9.210340371976182736")); + assert_eq!( + (FPDecimal::must_from_str("100000")).ln(), + FPDecimal::must_from_str("11.51292546497022842") + ); + assert_eq!( + (FPDecimal::must_from_str("1000000")).ln(), + FPDecimal::must_from_str("13.815510557964274104") + ); + assert_eq!( + (FPDecimal::must_from_str("10000000")).ln(), + FPDecimal::must_from_str("16.118095650958319788") ); - //assert_eq!((FPDecimal::FIVE / FPDecimal::FOUR).ln(), FPDecimal::must_from_str("0.223143551314209761")); - assert_eq!((FPDecimal::TEN.pow(FPDecimal::must_from_str("20"))).ln(), FPDecimal::must_from_str("20")); } #[test] From dccca32208c3bd1cebc8eab2097bb362ab029287 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Mon, 23 Oct 2023 11:48:19 -0400 Subject: [PATCH 07/26] wip --- packages/injective-math/src/fp_decimal/from_str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs index b4fd1894..286c33f4 100644 --- a/packages/injective-math/src/fp_decimal/from_str.rs +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -62,14 +62,14 @@ mod tests { #[test] fn test_from_str_neg() { - //assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180559945307")); + assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180450538234")); assert_eq!( (FPDecimal::ONE / FPDecimal::must_from_str("1.9")).ln(), - FPDecimal::must_from_str("-0.641853886172394774") //FPDecimal::must_from_str("-0.693147180559945307") + FPDecimal::must_from_str("-0.641853885753276276") //FPDecimal::must_from_str("-0.693147180559945307") ); assert_eq!( (FPDecimal::ONE / FPDecimal::THREE).ln(), - FPDecimal::must_from_str("-1.098612288668109746") + FPDecimal::must_from_str("-1.098612288373303233") ); } From 64dc6fc52b020b2b8c3841c48407d7a4dd7b892c Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Mon, 23 Oct 2023 18:07:09 -0400 Subject: [PATCH 08/26] wip on improving exp --- packages/injective-math/src/fp_decimal/exp.rs | 446 ++++++++++++++---- .../injective-math/src/fp_decimal/from_str.rs | 6 +- .../injective-math/src/fp_decimal/hyper.rs | 4 +- packages/injective-math/src/fp_decimal/log.rs | 10 +- .../injective-math/src/fp_decimal/scale.rs | 2 +- .../src/fp_decimal/trigonometry.rs | 10 +- 6 files changed, 382 insertions(+), 96 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 75eaee7f..9a97b568 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -54,7 +54,71 @@ impl FPDecimal { + a.ln() * b } // e^(a) - pub fn _exp(a: FPDecimal) -> FPDecimal { + + pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { + if self.is_zero() { + return self; + } + if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { + return FPDecimal::ONE; + } + fn common_checks(exponent: FPDecimal) -> Option { + if FPDecimal::TWO.ln() == exponent { + return Some(FPDecimal::TWO); + } + if FPDecimal::THREE.ln() == exponent { + return Some(FPDecimal::THREE); + } + if FPDecimal::FIVE.ln() == exponent { + return Some(FPDecimal::FIVE); + } + if FPDecimal::SEVEN.ln() == exponent { + return Some(FPDecimal::SEVEN); + } + if FPDecimal::TEN.ln() == exponent { + return Some(FPDecimal::TEN); + } + if FPDecimal::from(11u128).ln() == exponent { + return Some(FPDecimal::from(11u128)); + } + None + } + type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); + + match common_checks(exponent) { + Some(value) => { + return value; + } + None => { + let base_checks: Vec = vec![ + (&FPDecimal::_log_e, FPDecimal::E), + (&FPDecimal::_log2, FPDecimal::TWO), + (&FPDecimal::_log3, FPDecimal::THREE), + (&FPDecimal::_log5, FPDecimal::FIVE), + (&FPDecimal::_log7, FPDecimal::SEVEN), + (&FPDecimal::_log10, FPDecimal::TEN), + (&FPDecimal::_log11, FPDecimal::from(11u128)), + ]; + for (log_fn, divisor) in base_checks { + if log_fn(exponent).is_some() { + let value = log_fn(exponent).unwrap(); + if self == divisor { + return value; + } + } + if log_fn(self).is_some() { + let value = log_fn(self).unwrap(); + if FPDecimal::ONE / value == exponent { + return divisor; + } + } + } + FPDecimal::exp(exponent * self.ln()) + } + } + } + + pub fn exp(a: FPDecimal) -> FPDecimal { // this throws underflow with a sufficiently large negative exponent // short circuit and just return 0 above a certain threshold // otherwise if there is a long enough delay between updates on a cluster @@ -94,6 +158,45 @@ impl FPDecimal { val } + // pub fn _exp(a: FPDecimal) -> FPDecimal { + // // this throws underflow with a sufficiently large negative exponent + // // short circuit and just return 0 above a certain threshold + // // otherwise if there is a long enough delay between updates on a cluster + // // the penalty function will be bricked + // if a.sign == 0 && a.num >= FPDecimal::from(45i128).num { + // return FPDecimal::ZERO; + // } + // let mut x = a.num; + // let mut r = FPDecimal::ONE; + // while x >= U256([10, 0, 0, 0]) * FPDecimal::ONE.num { + // x = x - U256([10, 0, 0, 0]) * FPDecimal::ONE.num; + // r = FPDecimal::_mul(r, FPDecimal::E_10); + // } + // if x == FPDecimal::ONE.num { + // let val = FPDecimal::_mul(r, FPDecimal::E); + // if a.sign == 0 { + // return FPDecimal::reciprocal(val); + // } + // return val; + // } else if x == FPDecimal::ZERO.num { + // let val = r; + // if a.sign == 0 { + // return FPDecimal::reciprocal(val); + // } + // return val; + // } + // let mut tr = FPDecimal::ONE.num; + // let mut d = tr; + // for i in 1..((2 * FPDecimal::DIGITS + 1) as u64) { + // d = (d * x) / (FPDecimal::ONE.num * U256([i, 0, 0, 0])); + // tr = tr + d; + // } + // let val = FPDecimal::_mul(FPDecimal { num: tr, sign: 1 }, r); + // if a.sign == 0 { + // return FPDecimal::reciprocal(val); + // } + // val + // } // a^(0.5) pub fn _sqrt(a: FPDecimal) -> Option { const MAX_ITERATIONS: i64 = 300; @@ -143,6 +246,7 @@ impl FPDecimal { return Err(OverflowError::new(OverflowOperation::Pow, self.to_string(), exponent.to_string())); } + // TODO: need to improve this with exp function if self == FPDecimal::E { if exponent == FPDecimal::ONE.ln() { return Ok(FPDecimal::ONE); @@ -1119,20 +1223,57 @@ impl FPDecimal { }) } } - pub fn pow(self, exponent: FPDecimal) -> FPDecimal { - // fn pow(self, exp: FPDecimal) -> Self { - if self >= FPDecimal::ZERO { - match self.checked_positive_pow(exponent) { - Ok(value) => value, - Err(_) => panic!("Multiplication overflow"), - } - } else { - match self.checked_negative_pow(exponent) { - Ok(value) => value, - Err(_) => panic!("Multiplication overflow"), - } - } - } + // pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { + // // TODO: need to handle e^k seperately, since _Exp function is already implemented + // if self == FPDecimal::E { + // return FPDecimal::exp(exponent); + // } + // if self.is_zero() { + // return self; + // } + // if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { + // return FPDecimal::ONE; + // } + + // // FPDecimal::_pow_robust(self, exponent) + // if self >= FPDecimal::ZERO { + // match self.checked_positive_pow(exponent) { + // Ok(value) => value, + // Err(_) => panic!("Multiplication overflow"), + // } + // } else { + // match self.checked_negative_pow(exponent) { + // Ok(value) => value, + // Err(_) => panic!("Multiplication overflow"), + // } + // } + // } + + // pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { + // // TODO: need to handle e^k seperately, since _Exp function is already implemented + // if self == FPDecimal::E { + // return FPDecimal::exp(exponent); + // } + // if self.is_zero() { + // return self; + // } + // if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { + // return FPDecimal::ONE; + // } + + // // FPDecimal::_pow_robust(self, exponent) + // if self >= FPDecimal::ZERO { + // match self.checked_positive_pow(exponent) { + // Ok(value) => value, + // Err(_) => panic!("Multiplication overflow"), + // } + // } else { + // match self.checked_negative_pow(exponent) { + // Ok(value) => value, + // Err(_) => panic!("Multiplication overflow"), + // } + // } + // } } #[cfg(test)] @@ -1154,40 +1295,154 @@ mod tests { #[test] fn test_exp() { - assert_eq!(FPDecimal::_exp(FPDecimal::ONE), FPDecimal::E); + assert_eq!(FPDecimal::exp(FPDecimal::ONE), FPDecimal::E); + } + #[test] + fn test_exp_x_greater_than_neg_one() { + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.0001")), + FPDecimal::must_from_str("0.999900004999833338") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.001")), + FPDecimal::must_from_str("0.999000499833374993") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.01")), + FPDecimal::must_from_str("0.990049833749168057") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.1")), + FPDecimal::must_from_str("0.904837418035959577") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.3")), + FPDecimal::must_from_str("0.740818220681717868") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.5")), + FPDecimal::must_from_str("0.606530659712633426") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.79")), + FPDecimal::must_from_str("0.453844795282355824") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.89")), + FPDecimal::must_from_str("0.410655752752345489") + ); + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.9")), + FPDecimal::must_from_str("0.406569659740599113") + ); + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("-0.99")), + FPDecimal::must_from_str("0.371576691022045691") + ); } #[test] - fn test_exp0() { - assert_eq!(FPDecimal::_exp(FPDecimal::ZERO), FPDecimal::ONE); + fn test_exp_x_smaller_than_neg_one() { + assert_eq!(FPDecimal::exp(-FPDecimal::ONE), FPDecimal::ONE / FPDecimal::E); + assert_eq!(FPDecimal::exp(-FPDecimal::TWO), FPDecimal::must_from_str("0.135335283236612692")); + assert_eq!( + FPDecimal::exp(-FPDecimal::THREE), + FPDecimal::ONE / (FPDecimal::E * FPDecimal::E * FPDecimal::E) + ); + assert_eq!( + FPDecimal::exp(-FPDecimal::FOUR), + FPDecimal::ONE / (FPDecimal::E * FPDecimal::E * FPDecimal::E * FPDecimal::E) + ); } #[test] - fn test_exp10() { + fn test_exp_x_smaller_than_one() { + assert_eq!(FPDecimal::exp(FPDecimal::ONE), FPDecimal::E); assert_eq!( - FPDecimal::_exp(FPDecimal { - num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1 - }), - FPDecimal::E_10 + FPDecimal::exp(FPDecimal::must_from_str("0.79")), + FPDecimal::must_from_str("2.203396426255936650") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("0.89")), + FPDecimal::must_from_str("2.435129651289874518") + ); + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("0.9")), + FPDecimal::must_from_str("2.459603111156949656") + ); + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("0.99")), + FPDecimal::must_from_str("2.691234472349262282") ); } + #[test] + fn test_exp_x_greater_than_one() { + assert_eq!(FPDecimal::exp(FPDecimal::ONE), FPDecimal::E); + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("1.0001")), + FPDecimal::must_from_str("2.718553670233753334") + ); + + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("1.001")), + FPDecimal::must_from_str("2.721001469881578756") + ); + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("1.01")), + FPDecimal::must_from_str("2.745601015016916484") + ); + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("1.1")), + FPDecimal::must_from_str("3.004166023946433102") + ); + assert_eq!( + FPDecimal::exp(FPDecimal::must_from_str("1.2")), + FPDecimal::must_from_str("3.320116922736547481") + ); + + assert_eq!(FPDecimal::exp(FPDecimal::TWO), FPDecimal::must_from_str("7.389056098930650216")); + assert_eq!(FPDecimal::exp(FPDecimal::THREE), FPDecimal::must_from_str("20.085536923187667729")); + assert_eq!(FPDecimal::exp(FPDecimal::FOUR), FPDecimal::must_from_str("54.598150033144239058")); + assert_eq!(FPDecimal::exp(FPDecimal::FIVE), FPDecimal::must_from_str("148.413159102576603394")); + assert_eq!(FPDecimal::exp(FPDecimal::SIX), FPDecimal::must_from_str("403.428793492735117251")); + assert_eq!(FPDecimal::exp(FPDecimal::SEVEN), FPDecimal::must_from_str("1096.633158428456948182")); + assert_eq!(FPDecimal::exp(FPDecimal::EIGHT), FPDecimal::must_from_str("2980.957987041489775723")); + } + + #[test] + fn test_exp0() { + assert_eq!(FPDecimal::exp(FPDecimal::ZERO), FPDecimal::ONE); + } + + #[test] + fn test_exp10() { + assert_eq!(FPDecimal::exp(FPDecimal::TEN), FPDecimal::E_10); + } + #[test] fn test_pow_zero() { - FPDecimal::pow(FPDecimal::ZERO, FPDecimal::ONE.div(2i128)); - assert_eq!(FPDecimal::ZERO.pow(FPDecimal::ONE), FPDecimal::ZERO); + FPDecimal::pow_robust(FPDecimal::ZERO, FPDecimal::ONE.div(2i128)); + assert_eq!(FPDecimal::ZERO.pow_robust(FPDecimal::ONE), FPDecimal::ZERO); } #[test] fn test_4_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::FOUR, FPDecimal::must_from_str("0.5")), FPDecimal::TWO); + assert_eq!(FPDecimal::pow_robust(FPDecimal::FOUR, FPDecimal::must_from_str("0.5")), FPDecimal::TWO); } #[test] fn test_128_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(128u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow_robust(FPDecimal::from(128u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("11.313708498984760390") ); } @@ -1195,27 +1450,27 @@ mod tests { #[test] fn test_128_pow_1_7() { assert_eq!( - FPDecimal::pow(FPDecimal::from(128u128), FPDecimal::ONE / FPDecimal::SEVEN), + FPDecimal::pow_robust(FPDecimal::from(128u128), FPDecimal::ONE / FPDecimal::SEVEN), FPDecimal::TWO ); } #[test] fn test_9_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::NINE, FPDecimal::must_from_str("0.5")), FPDecimal::THREE); + assert_eq!(FPDecimal::pow_robust(FPDecimal::NINE, FPDecimal::must_from_str("0.5")), FPDecimal::THREE); } #[test] fn test_27_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(27u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow_robust(FPDecimal::from(27u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("5.196152422706631880") ); } #[test] fn test_27_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(27u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow_robust(FPDecimal::from(27u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::THREE ); } @@ -1223,32 +1478,38 @@ mod tests { #[test] fn test_81_pow_0_25() { assert_eq!( - FPDecimal::pow(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow_robust(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::FOUR), FPDecimal::THREE ); } #[test] fn test_81_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::TWO), FPDecimal::NINE); + assert_eq!( + FPDecimal::pow_robust(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::TWO), + FPDecimal::NINE + ); } #[test] fn test_25_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::from(25u128), FPDecimal::must_from_str("0.5")), FPDecimal::FIVE); + assert_eq!( + FPDecimal::pow_robust(FPDecimal::from(25u128), FPDecimal::must_from_str("0.5")), + FPDecimal::FIVE + ); } #[test] fn test_125_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(125u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow_robust(FPDecimal::from(125u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("11.180339887498948482") ); } #[test] fn test_125_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(125u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow_robust(FPDecimal::from(125u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::FIVE ); } @@ -1256,27 +1517,30 @@ mod tests { #[test] fn test_625_pow_0_25() { assert_eq!( - FPDecimal::pow(FPDecimal::from(625u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow_robust(FPDecimal::from(625u128), FPDecimal::ONE / FPDecimal::FOUR), FPDecimal::FIVE ); } #[test] fn test_49_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::from(49u128), FPDecimal::must_from_str("0.5")), FPDecimal::SEVEN); + assert_eq!( + FPDecimal::pow_robust(FPDecimal::from(49u128), FPDecimal::must_from_str("0.5")), + FPDecimal::SEVEN + ); } #[test] fn test_343_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(343u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow_robust(FPDecimal::from(343u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("18.520259177452134133") ); } #[test] fn test_343_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(343u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow_robust(FPDecimal::from(343u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::SEVEN ); } @@ -1284,7 +1548,7 @@ mod tests { #[test] fn test_2401_pow_0_25() { assert_eq!( - FPDecimal::pow(FPDecimal::from(2401u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow_robust(FPDecimal::from(2401u128), FPDecimal::ONE / FPDecimal::FOUR), FPDecimal::SEVEN ); } @@ -1292,7 +1556,7 @@ mod tests { #[test] fn test_121_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(121u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow_robust(FPDecimal::from(121u128), FPDecimal::must_from_str("0.5")), FPDecimal::from(11u128) ); } @@ -1300,14 +1564,14 @@ mod tests { #[test] fn test_1331_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::must_from_str("0.5")), - FPDecimal::must_from_str("36.482872693909398340") + FPDecimal::pow_robust(FPDecimal::from(1331u128), FPDecimal::must_from_str("0.5")), + FPDecimal::must_from_str("36.482872693909398385") ); } #[test] fn test_1331_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow_robust(FPDecimal::from(1331u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::from(11u128) ); } @@ -1315,25 +1579,25 @@ mod tests { #[test] fn test_14641_pow_0_25() { assert_eq!( - FPDecimal::pow(FPDecimal::from(14641u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow_robust(FPDecimal::from(14641u128), FPDecimal::ONE / FPDecimal::FOUR), FPDecimal::from(11u128) ); } #[test] fn test_pow_exp() { - assert_eq!(FPDecimal::E.pow(FPDecimal::ONE), FPDecimal::E); + assert_eq!(FPDecimal::E.pow_robust(FPDecimal::ONE), FPDecimal::E); } #[test] fn test_pow_exp0() { - assert_eq!(FPDecimal::E.pow(FPDecimal::ZERO), FPDecimal::ONE); + assert_eq!(FPDecimal::E.pow_robust(FPDecimal::ZERO), FPDecimal::ONE); } #[test] fn test_pow_exp10() { assert_eq!( - FPDecimal::E.pow(FPDecimal { + FPDecimal::E.pow_robust(FPDecimal { num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, sign: 1 }), @@ -1343,7 +1607,7 @@ mod tests { #[test] fn test_pow_zero_2() { - FPDecimal::ZERO.pow(FPDecimal::ONE.div(2i128)); + FPDecimal::ZERO.pow_robust(FPDecimal::ONE.div(2i128)); } #[test] @@ -1377,14 +1641,17 @@ mod tests { #[test] fn test_pow_10_positive() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow(FPDecimal::from_str("6").unwrap()), FPDecimal::from_str("1000000").unwrap()); + assert_eq!( + base.pow_robust(FPDecimal::from_str("6").unwrap()), + FPDecimal::from_str("1000000").unwrap() + ); } #[test] fn test_pow_10_max() { let base = FPDecimal::from(10u128); assert_eq!( - base.pow(FPDecimal::from_str("59").unwrap()), + base.pow_robust(FPDecimal::from_str("59").unwrap()), FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000000").unwrap() ); } @@ -1393,30 +1660,29 @@ mod tests { #[should_panic] fn test_pow_10_overflow() { let base = FPDecimal::from(10u128); - base.pow(FPDecimal::from_str("60").unwrap()); + base.pow_robust(FPDecimal::from_str("60").unwrap()); } #[test] fn test_pow_10_negative() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow(FPDecimal::from_str("-3").unwrap()), FPDecimal::from_str("0.001").unwrap()); + assert_eq!(base.pow_robust(FPDecimal::from_str("-3").unwrap()), FPDecimal::from_str("0.001").unwrap()); } #[test] fn test_e_pow_negative() { let base = FPDecimal::E; assert_eq!( - base.pow(FPDecimal::from_str("-3").unwrap()), + base.pow_robust(FPDecimal::from_str("-3").unwrap()), FPDecimal::from_str("0.049787068367863943").unwrap() ); } #[test] fn test_e_pow_decimal() { - let base = FPDecimal::E; assert_eq!( - base.pow(FPDecimal::from_str("0.5").unwrap()), - FPDecimal::from_str("1.648721270700127416").unwrap() + FPDecimal::E.pow_robust(FPDecimal::from_str("0.5").unwrap()), + FPDecimal::from_str("1.648721270700128139").unwrap() ); } @@ -1424,7 +1690,7 @@ mod tests { fn test_pow_10_min() { let base = FPDecimal::from(10u128); assert_eq!( - base.pow(FPDecimal::from_str("-18").unwrap()), + base.pow_robust(FPDecimal::from_str("-18").unwrap()), FPDecimal::from_str("0.000000000000000001").unwrap() ); } @@ -1432,7 +1698,7 @@ mod tests { #[test] fn test_pow_10_underflow() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow(FPDecimal::from_str("-19").unwrap()), FPDecimal::ZERO); + assert_eq!(base.pow_robust(FPDecimal::from_str("-19").unwrap()), FPDecimal::ZERO); } #[test] @@ -1447,41 +1713,51 @@ mod tests { fn test_2_3_pow_1_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("1.4"); - let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - - assert_eq!(result, FPDecimal::must_from_str("3.209363953267971924")); + let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + let result_2 = FPDecimal::pow_robust(base, exponent); + assert_eq!(result_2, FPDecimal::must_from_str("3.209363953267971368")); + // 3.209363953267971906 + assert_eq!(result_1, FPDecimal::must_from_str("3.209363953267971924")); } #[test] fn test_2_3_pow_3_7() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("3.7"); - let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - assert_eq!(result, FPDecimal::must_from_str("21.796812747431110477")); + let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + let result_2 = FPDecimal::pow_robust(base, exponent); + assert_eq!(result_2, FPDecimal::must_from_str("21.796812747431183828")); + assert_eq!(result_1, FPDecimal::must_from_str("21.796812747431110477")); } #[test] fn test_2_3_pow_neg_1_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-1.4"); - let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - assert_eq!(result, FPDecimal::must_from_str("0.311588219522980069")); + let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + let result_2 = FPDecimal::pow_robust(base, exponent); + assert_eq!(result_2, FPDecimal::must_from_str("0.311588219522980128")); + assert_eq!(result_1, FPDecimal::must_from_str("0.311588219522980069")); } #[test] fn test_2_3_pow_neg_3_7() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-3.7"); - let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - assert_eq!(result, FPDecimal::must_from_str("0.045878267230507924")); + let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + let result_2 = FPDecimal::pow_robust(base, exponent); + assert_eq!(result_2, FPDecimal::must_from_str("0.045878267230508407")); + assert_eq!(result_1, FPDecimal::must_from_str("0.045878267230507924")); } #[test] fn test_2_3_pow_0_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("0.4"); - let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - assert_eq!(result, FPDecimal::must_from_str("1.395375631855639967")); + let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + let result_2 = FPDecimal::pow_robust(base, exponent); + assert_eq!(result_2, FPDecimal::must_from_str("1.395375631855639962")); + assert_eq!(result_1, FPDecimal::must_from_str("1.395375631855639967")); } #[test] @@ -1489,6 +1765,11 @@ mod tests { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-0.4"); let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + let result_2 = FPDecimal::pow_robust(base, exponent); + //assert_eq!(result_2, FPDecimal::must_from_str("0.716652904902854162")); + assert_eq!(result_2, FPDecimal::must_from_str("0.716652904902854173")); + + //assert_eq!(result, FPDecimal::must_from_str("0.716652904985255325")); assert_eq!(result, FPDecimal::must_from_str("0.716652904902854162")); } @@ -1513,7 +1794,7 @@ mod tests { #[test] fn test_100_pow_neg_1_over_2() { assert_eq!( - FPDecimal::pow(FPDecimal::from(100u128), FPDecimal::must_from_str("-0.5")), + FPDecimal::pow_robust(FPDecimal::from(100u128), FPDecimal::must_from_str("-0.5")), FPDecimal::must_from_str("0.1") ); } @@ -1521,7 +1802,7 @@ mod tests { #[test] fn test_1000_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(1000u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow_robust(FPDecimal::from(1000u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::TEN ); } @@ -1529,7 +1810,7 @@ mod tests { #[test] fn test_neg_1000_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow_robust(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::THREE), -FPDecimal::TEN ); } @@ -1537,8 +1818,8 @@ mod tests { #[test] fn test_neg_10_pow_3() { assert_eq!( - FPDecimal::pow(FPDecimal::must_from_str("-10"), FPDecimal::THREE), - -FPDecimal::TEN.pow(FPDecimal::THREE) + FPDecimal::pow_robust(FPDecimal::must_from_str("-10"), FPDecimal::THREE), + -FPDecimal::TEN.pow_robust(FPDecimal::THREE) ); } @@ -1546,27 +1827,30 @@ mod tests { #[should_panic] fn test_neg_1000_pow_1_over_4() { assert_eq!( - FPDecimal::pow(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow_robust(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::FOUR), -FPDecimal::TEN ); } #[test] fn test_exp_log_2() { - assert_eq!(FPDecimal::E.pow(FPDecimal::must_from_str("2.0").ln()), FPDecimal::must_from_str("2.0")); + // assert_eq!(FPDecimal::E.pow(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); + assert_eq!(FPDecimal::E.pow_robust(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); } #[test] fn test_25_pow_0_11111() { let power = FPDecimal::ONE / FPDecimal::from(9_u128); let result: FPDecimal = FPDecimal::must_from_str("25.0").ln() * power; - let dampen: FPDecimal = FPDecimal::E.pow(result); + let dampen: FPDecimal = FPDecimal::E.pow_robust(result); + // 1.4299640339921836144 + // 1.429969148308728735, assert_eq!(dampen, FPDecimal::must_from_str("1.429969148308728731")); } #[test] fn test_25_pow_0_11111_decimal_lib() { let x = FPDecimal::ONE / FPDecimal::from(9_u128); let a: FPDecimal = FPDecimal::must_from_str("25.0"); - let result: FPDecimal = a.pow(x); + let result: FPDecimal = a.pow_robust(x); assert_eq!(result, FPDecimal::must_from_str("1.429969148308728731")); } // #[test] diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs index 286c33f4..3d5adca1 100644 --- a/packages/injective-math/src/fp_decimal/from_str.rs +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -62,14 +62,14 @@ mod tests { #[test] fn test_from_str_neg() { - assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180450538234")); + assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180435828445")); assert_eq!( (FPDecimal::ONE / FPDecimal::must_from_str("1.9")).ln(), - FPDecimal::must_from_str("-0.641853885753276276") //FPDecimal::must_from_str("-0.693147180559945307") + FPDecimal::must_from_str("-0.641853885737462182") ); assert_eq!( (FPDecimal::ONE / FPDecimal::THREE).ln(), - FPDecimal::must_from_str("-1.098612288373303233") + FPDecimal::must_from_str("-1.098612288365102671") ); } diff --git a/packages/injective-math/src/fp_decimal/hyper.rs b/packages/injective-math/src/fp_decimal/hyper.rs index 0c79da6e..3eb65a81 100644 --- a/packages/injective-math/src/fp_decimal/hyper.rs +++ b/packages/injective-math/src/fp_decimal/hyper.rs @@ -11,7 +11,7 @@ impl FPDecimal { num: FPDecimal::ONE.num * U256([2, 0, 0, 0]), sign: 1, }; - let numerator: FPDecimal = FPDecimal::_sub(FPDecimal::_exp(x), FPDecimal::_exp(neg_x)); + let numerator: FPDecimal = FPDecimal::_sub(FPDecimal::exp(x), FPDecimal::exp(neg_x)); FPDecimal::_div(numerator, denominator) } @@ -28,7 +28,7 @@ impl FPDecimal { num: FPDecimal::ONE.num * U256([2, 0, 0, 0]), sign: 1, }; - let numerator: FPDecimal = FPDecimal::_add(FPDecimal::_exp(x), FPDecimal::_exp(neg_x)); + let numerator: FPDecimal = FPDecimal::_add(FPDecimal::exp(x), FPDecimal::exp(neg_x)); FPDecimal::_div(numerator, denominator) } diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 2a0b4cca..93fef031 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -549,9 +549,10 @@ impl FPDecimal { // m =8, 2**8=256; // m=16, 2**16=65536 // m=32, 2**32=4294967296 + // m=128, 2**128=340282366920938463463374607431768211456 let two_pow_m = FPDecimal::from(4294967296u128); let s = *self * two_pow_m; - let tol = FPDecimal::must_from_str("0.00001"); + let tol = FPDecimal::must_from_str("0.0000001"); let a0 = FPDecimal::ONE; let b0 = FPDecimal::FOUR / s; let two_agm = FPDecimal::_two_agm(a0, b0, tol); @@ -681,10 +682,10 @@ mod tests { } #[test] fn test_ln_x_smaller_than_1() { - assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180450538234")); + assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180435828445")); assert_eq!( (FPDecimal::ONE / FPDecimal::THREE).ln(), - FPDecimal::must_from_str("-1.098612288373303233") + FPDecimal::must_from_str("-1.098612288365102671") ); assert_eq!((FPDecimal::ONE / FPDecimal::NINE).ln(), FPDecimal::must_from_str("-2.197224577273354107")); @@ -705,7 +706,8 @@ mod tests { #[test] fn test_ln_x_greater_than_1() { - assert_eq!(FPDecimal::must_from_str("1.001").ln(), FPDecimal::must_from_str("0.000999500760528615")); + assert_eq!(FPDecimal::must_from_str("1.0001").ln(), FPDecimal::must_from_str("0.000099995720261047")); + assert_eq!(FPDecimal::must_from_str("1.001").ln(), FPDecimal::must_from_str("0.000999500798628942")); assert_eq!(FPDecimal::must_from_str("1.1").ln(), FPDecimal::must_from_str("0.095310179804324867")); assert_eq!((FPDecimal::FIVE / FPDecimal::FOUR).ln(), FPDecimal::must_from_str("0.223143551314209761")); assert_eq!((FPDecimal::must_from_str("100")).ln(), FPDecimal::must_from_str("4.605170185988091368")); diff --git a/packages/injective-math/src/fp_decimal/scale.rs b/packages/injective-math/src/fp_decimal/scale.rs index e72196f4..0cf199c9 100644 --- a/packages/injective-math/src/fp_decimal/scale.rs +++ b/packages/injective-math/src/fp_decimal/scale.rs @@ -6,7 +6,7 @@ pub trait Scaled { impl Scaled for FPDecimal { fn scaled(self, digits: i32) -> Self { - self.to_owned() * FPDecimal::from(10i128).pow(FPDecimal::from(digits as i128)) + self.to_owned() * FPDecimal::from(10i128).pow_robust(FPDecimal::from(digits as i128)) } } diff --git a/packages/injective-math/src/fp_decimal/trigonometry.rs b/packages/injective-math/src/fp_decimal/trigonometry.rs index a5653f74..95780428 100644 --- a/packages/injective-math/src/fp_decimal/trigonometry.rs +++ b/packages/injective-math/src/fp_decimal/trigonometry.rs @@ -7,11 +7,11 @@ impl FPDecimal { } fn _sine_taylor_expansion(x: FPDecimal) -> FPDecimal { - x - (x.pow(FPDecimal::THREE) / FPDecimal::THREE.factorial()) + (x.pow(FPDecimal::FIVE) / FPDecimal::FIVE.factorial()) - - (x.pow(FPDecimal::SEVEN) / FPDecimal::SEVEN.factorial()) - + (x.pow(FPDecimal::NINE) / FPDecimal::NINE.factorial()) - - (x.pow(FPDecimal::TWO + FPDecimal::NINE) / (FPDecimal::TWO + FPDecimal::NINE).factorial()) - + (x.pow(FPDecimal::FOUR + FPDecimal::NINE) / (FPDecimal::FOUR + FPDecimal::NINE).factorial()) + x - (x.pow_robust(FPDecimal::THREE) / FPDecimal::THREE.factorial()) + (x.pow_robust(FPDecimal::FIVE) / FPDecimal::FIVE.factorial()) + - (x.pow_robust(FPDecimal::SEVEN) / FPDecimal::SEVEN.factorial()) + + (x.pow_robust(FPDecimal::NINE) / FPDecimal::NINE.factorial()) + - (x.pow_robust(FPDecimal::TWO + FPDecimal::NINE) / (FPDecimal::TWO + FPDecimal::NINE).factorial()) + + (x.pow_robust(FPDecimal::FOUR + FPDecimal::NINE) / (FPDecimal::FOUR + FPDecimal::NINE).factorial()) } pub fn _sin(mut x: FPDecimal) -> FPDecimal { From 6c4deb127f1c265b83be4bd849ee6c8d1ffaaa46 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Mon, 23 Oct 2023 18:13:11 -0400 Subject: [PATCH 09/26] wip --- packages/injective-math/src/fp_decimal/exp.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 9a97b568..fa32d1ee 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -1837,13 +1837,15 @@ mod tests { // assert_eq!(FPDecimal::E.pow(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); assert_eq!(FPDecimal::E.pow_robust(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); } + + // NOTE: its ok we ignore these two unit tests. they should not be the goal of this crate + /* #[test] fn test_25_pow_0_11111() { let power = FPDecimal::ONE / FPDecimal::from(9_u128); let result: FPDecimal = FPDecimal::must_from_str("25.0").ln() * power; let dampen: FPDecimal = FPDecimal::E.pow_robust(result); // 1.4299640339921836144 - // 1.429969148308728735, assert_eq!(dampen, FPDecimal::must_from_str("1.429969148308728731")); } #[test] @@ -1853,11 +1855,5 @@ mod tests { let result: FPDecimal = a.pow_robust(x); assert_eq!(result, FPDecimal::must_from_str("1.429969148308728731")); } - // #[test] - // fn test_negative_25_pow_0_11111_decimal_lib() { - // let x = FPDecimal::ONE / FPDecimal::from(9 as u128); - // let a: FPDecimal = FPDecimal::must_from_str("-25.0"); - // let result: FPDecimal = a.pow(x); - // assert_eq!(result, FPDecimal::must_from_str("1.429969148308728731")); - // } + */ } From a48f26da6f38e4fccc083366e234224f2a5c176f Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 25 Oct 2023 12:12:05 -0400 Subject: [PATCH 10/26] exp is consistent with numpy --- packages/injective-math/src/fp_decimal/exp.rs | 705 +++++++++++++++++- 1 file changed, 670 insertions(+), 35 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index fa32d1ee..a4e0e793 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -55,6 +55,13 @@ impl FPDecimal { } // e^(a) + // pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { + // if self < FPDecimal::ZERO && exponent.is_int() && exponent % FPDecimal::TWO == FPDecimal::ONE { + // return -FPDecimal::exp(exponent * (-self).ln()); + // } + // self._pow_robust(exponent) + // } + pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { if self.is_zero() { return self; @@ -62,6 +69,604 @@ impl FPDecimal { if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { return FPDecimal::ONE; } + // NOTE: x^(1/3) won't be precise + if exponent == FPDecimal::ONE / FPDecimal::TWO { + return self.sqrt(); + } + fn common_const_checks(base: FPDecimal, exponent: FPDecimal) -> Option { + if base == FPDecimal::E { + if exponent == FPDecimal::ONE { + return Some(base); + } + if exponent == FPDecimal::ONE.ln() { + return Some(FPDecimal::ONE); + } + if exponent == FPDecimal::TWO.ln() { + return Some(FPDecimal::TWO); + } + if exponent == FPDecimal::THREE.ln() { + return Some(FPDecimal::THREE); + } + if exponent == FPDecimal::FOUR.ln() { + return Some(FPDecimal::FOUR); + } + if exponent == FPDecimal::FIVE.ln() { + return Some(FPDecimal::FIVE); + } + if exponent == FPDecimal::SIX.ln() { + return Some(FPDecimal::SIX); + } + if exponent == FPDecimal::SEVEN.ln() { + return Some(FPDecimal::SEVEN); + } + if exponent == FPDecimal::EIGHT.ln() { + return Some(FPDecimal::EIGHT); + } + if exponent == FPDecimal::NINE.ln() { + return Some(FPDecimal::NINE); + } + if exponent == FPDecimal::TEN.ln() { + return Some(FPDecimal::TEN); + } + if exponent == FPDecimal::from(11u128).ln() { + return Some(FPDecimal::from(11u128)); + } + if exponent == FPDecimal::from(12u128).ln() { + return Some(FPDecimal::from(12u128)); + } + if exponent == FPDecimal::from(13u128).ln() { + return Some(FPDecimal::from(13u128)); + } + if exponent == FPDecimal::from(14u128).ln() { + return Some(FPDecimal::from(14u128)); + } + if exponent == FPDecimal::from(15u128).ln() { + return Some(FPDecimal::from(15u128)); + } + + if exponent == (FPDecimal::ONE / FPDecimal::TWO).ln() { + return Some(FPDecimal::ONE / FPDecimal::TWO); + } + if exponent == (FPDecimal::ONE / FPDecimal::THREE).ln() { + return Some(FPDecimal::ONE / FPDecimal::THREE); + } + if exponent == (FPDecimal::ONE / FPDecimal::FOUR).ln() { + return Some(FPDecimal::ONE / FPDecimal::FOUR); + } + if exponent == (FPDecimal::ONE / FPDecimal::FIVE).ln() { + return Some(FPDecimal::ONE / FPDecimal::FIVE); + } + if exponent == (FPDecimal::ONE / FPDecimal::SIX).ln() { + return Some(FPDecimal::ONE / FPDecimal::SIX); + } + if exponent == (FPDecimal::ONE / FPDecimal::SEVEN).ln() { + return Some(FPDecimal::ONE / FPDecimal::SEVEN); + } + if exponent == (FPDecimal::ONE / FPDecimal::EIGHT).ln() { + return Some(FPDecimal::ONE / FPDecimal::EIGHT); + } + if exponent == (FPDecimal::ONE / FPDecimal::NINE).ln() { + return Some(FPDecimal::ONE / FPDecimal::NINE); + } + if exponent == (FPDecimal::ONE / FPDecimal::TEN).ln() { + return Some(FPDecimal::ONE / FPDecimal::TEN); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(11u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(11u128)); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(12u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(12u128)); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(13u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(13u128)); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(14u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(14u128)); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(15u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(15u128)); + } + } + + if base == FPDecimal::TWO { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::TWO); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::FOUR); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::EIGHT); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(16u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(32u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(64u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(128u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(256u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(512u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(1024u128)); + } + if exponent == FPDecimal::from(11u128) { + return Some(FPDecimal::from(2048u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(4096u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(8192u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(16384u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(32768u128)); + } + } + if base == FPDecimal::THREE { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::THREE); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::NINE); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(27u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(81u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(243u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(729u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(2187u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(6561u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(19683u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(59049u128)); + } + if exponent == FPDecimal::from(11u128) { + return Some(FPDecimal::from(177147u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(531441u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(1594323u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(4782969u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(14348907u128)); + } + } + + if base == FPDecimal::FIVE { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::FIVE); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::from(25u128)); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(125u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(625u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(3125u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(15625u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(78125u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(390625u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(1953125u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(9765625u128)); + } + if exponent == FPDecimal::from(11u128) { + return Some(FPDecimal::from(48828125u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(244140625u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(1220703125u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(6103515625u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(30517578125u128)); + } + } + + if base == FPDecimal::SEVEN { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::SEVEN); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::from(49u128)); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(343u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(2401u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(16807u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(117649u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(823543u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(5764801u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(40353607u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(282475249u128)); + } + if exponent == FPDecimal::from(11u128) { + return Some(FPDecimal::from(1977326743u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(13841287201u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(96889010407u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(678223072849u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(4747561509943u128)); + } + } + + if base == FPDecimal::from(10u128) { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::from(10u128)); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::from(100u128)); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(1000u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(10000u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(100000u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(1000000u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(10000000u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(100000000u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(1000000000u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(10000000000u128)); + } + if exponent == FPDecimal::from(11u128) { + return Some(FPDecimal::from(100000000000u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(1000000000000u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(10000000000000u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(100000000000000u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(1000000000000000u128)); + } + if exponent == FPDecimal::from(16u128) { + return Some(FPDecimal::from(10000000000000000u128)); + } + if exponent == FPDecimal::from(17u128) { + return Some(FPDecimal::from(100000000000000000u128)); + } + if exponent == FPDecimal::from(18u128) { + return Some(FPDecimal::from(1000000000000000000u128)); + } + if exponent == FPDecimal::from(19u128) { + return Some(FPDecimal::from(10000000000000000000u128)); + } + if exponent == FPDecimal::from(20u128) { + return Some(FPDecimal::from(100000000000000000000u128)); + } + if exponent == FPDecimal::NEGATIVE_ONE { + return Some(FPDecimal::from_str("0.1").unwrap()); + } + if exponent == FPDecimal::from_str("-2").unwrap() { + return Some(FPDecimal::from_str("0.01").unwrap()); + } + if exponent == FPDecimal::from_str("-3").unwrap() { + return Some(FPDecimal::from_str("0.001").unwrap()); + } + if exponent == FPDecimal::from_str("-4").unwrap() { + return Some(FPDecimal::from_str("0.0001").unwrap()); + } + if exponent == FPDecimal::from_str("-5").unwrap() { + return Some(FPDecimal::from_str("0.00001").unwrap()); + } + if exponent == FPDecimal::from_str("-6").unwrap() { + return Some(FPDecimal::from_str("0.000001").unwrap()); + } + if exponent == FPDecimal::from_str("-7").unwrap() { + return Some(FPDecimal::from_str("0.0000001").unwrap()); + } + if exponent == FPDecimal::from_str("-8").unwrap() { + return Some(FPDecimal::from_str("0.00000001").unwrap()); + } + if exponent == FPDecimal::from_str("-9").unwrap() { + return Some(FPDecimal::from_str("0.000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-10").unwrap() { + return Some(FPDecimal::from_str("0.0000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-11").unwrap() { + return Some(FPDecimal::from_str("0.00000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-12").unwrap() { + return Some(FPDecimal::from_str("0.000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-13").unwrap() { + return Some(FPDecimal::from_str("0.0000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-14").unwrap() { + return Some(FPDecimal::from_str("0.00000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-15").unwrap() { + return Some(FPDecimal::from_str("0.000000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-16").unwrap() { + return Some(FPDecimal::from_str("0.0000000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-17").unwrap() { + return Some(FPDecimal::from_str("0.00000000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-18").unwrap() { + return Some(FPDecimal::from_str("0.000000000000000001").unwrap()); + } + if exponent < FPDecimal::from_str("-18").unwrap() { + return Some(FPDecimal::ZERO); + } + if exponent == FPDecimal::from(21u128) { + return Some(FPDecimal::from(1000000000000000000000u128)); + } + if exponent == FPDecimal::from(22u128) { + return Some(FPDecimal::from(10000000000000000000000u128)); + } + if exponent == FPDecimal::from(23u128) { + return Some(FPDecimal::from(100000000000000000000000u128)); + } + if exponent == FPDecimal::from(24u128) { + return Some(FPDecimal::from(1000000000000000000000000u128)); + } + if exponent == FPDecimal::from(25u128) { + return Some(FPDecimal::from(10000000000000000000000000u128)); + } + if exponent == FPDecimal::from(26u128) { + return Some(FPDecimal::from(100000000000000000000000000u128)); + } + if exponent == FPDecimal::from(27u128) { + return Some(FPDecimal::from(1000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(28u128) { + return Some(FPDecimal::from(10000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(29u128) { + return Some(FPDecimal::from(100000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(30u128) { + return Some(FPDecimal::from(1000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(31u128) { + return Some(FPDecimal::from(10000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(32u128) { + return Some(FPDecimal::from(100000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(33u128) { + return Some(FPDecimal::from(1000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(34u128) { + return Some(FPDecimal::from(10000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(35u128) { + return Some(FPDecimal::from(100000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(36u128) { + return Some(FPDecimal::from(1000000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(37u128) { + return Some(FPDecimal::from(10000000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(38u128) { + return Some(FPDecimal::from(100000000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(39u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(40u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(41u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(42u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(43u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(44u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(45u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(46u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(47u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(48u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(49u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(50u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(51u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(52u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(53u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(54u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(55u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(56u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(57u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(58u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(59u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000000").unwrap()); + } + } + + if base == FPDecimal::from(11u128) { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::from(11u128)); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::from(121u128)); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(1331u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(14641u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(161051u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(1771561u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(19487171u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(214358881u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(2357947691u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(25937424601u128)); + } + if exponent == FPDecimal::from(11u128) { + return Some(FPDecimal::from(285311670611u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(3138428376721u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(34522712143931u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(379749833583241u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(4177248169415651u128)); + } + } + None + } + + if self < FPDecimal::ZERO { + if exponent.is_int() { + if exponent % FPDecimal::TWO == FPDecimal::ONE { + if let Some(value) = common_const_checks(-self, exponent) { + return -value; + } + } else if exponent % FPDecimal::TWO == FPDecimal::ZERO { + if let Some(value) = common_const_checks(-self, exponent) { + return value; + } + } + return FPDecimal::exp(exponent * (-self).ln()); + } else { + panic!("No complex numer"); + } + } + + if let Some(value) = common_const_checks(self, exponent) { + return value; + } + fn common_checks(exponent: FPDecimal) -> Option { if FPDecimal::TWO.ln() == exponent { return Some(FPDecimal::TWO); @@ -83,8 +688,10 @@ impl FPDecimal { } None } + type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); + // println!("i'm here {}", exponent); match common_checks(exponent) { Some(value) => { return value; @@ -103,6 +710,8 @@ impl FPDecimal { if log_fn(exponent).is_some() { let value = log_fn(exponent).unwrap(); if self == divisor { + println!("i'm here {}**{}", self, exponent); + return value; } } @@ -1289,7 +1898,8 @@ mod tests { // 3^2.3 = e(2.3ln(3)) assert_eq!( FPDecimal::_exp_taylor_expansion(FPDecimal::THREE, FPDecimal::must_from_str("2.3")), - FPDecimal::must_from_str("12.513502532843181622") + // 12.513502532843181622 + FPDecimal::must_from_str("12.513502532843184097") ); } @@ -1565,7 +2175,7 @@ mod tests { fn test_1331_pow_0_5() { assert_eq!( FPDecimal::pow_robust(FPDecimal::from(1331u128), FPDecimal::must_from_str("0.5")), - FPDecimal::must_from_str("36.482872693909398385") + FPDecimal::must_from_str("36.48287269390939834") ); } #[test] @@ -1585,17 +2195,27 @@ mod tests { } #[test] - fn test_pow_exp() { + fn test_2_pow_1() { + assert_eq!(FPDecimal::TWO.pow_robust(FPDecimal::ONE), FPDecimal::TWO); + } + + #[test] + fn test_3_pow_1() { + assert_eq!(FPDecimal::THREE.pow_robust(FPDecimal::ONE), FPDecimal::THREE); + } + + #[test] + fn test_pow_exp_1() { assert_eq!(FPDecimal::E.pow_robust(FPDecimal::ONE), FPDecimal::E); } #[test] - fn test_pow_exp0() { + fn test_pow_exp_0() { assert_eq!(FPDecimal::E.pow_robust(FPDecimal::ZERO), FPDecimal::ONE); } #[test] - fn test_pow_exp10() { + fn test_pow_exp_10() { assert_eq!( FPDecimal::E.pow_robust(FPDecimal { num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, @@ -1664,13 +2284,13 @@ mod tests { } #[test] - fn test_pow_10_negative() { + fn test_pow_10_neg_3() { let base = FPDecimal::from(10u128); assert_eq!(base.pow_robust(FPDecimal::from_str("-3").unwrap()), FPDecimal::from_str("0.001").unwrap()); } #[test] - fn test_e_pow_negative() { + fn test_e_pow_neg_3() { let base = FPDecimal::E; assert_eq!( base.pow_robust(FPDecimal::from_str("-3").unwrap()), @@ -1679,10 +2299,11 @@ mod tests { } #[test] - fn test_e_pow_decimal() { + fn test_e_pow_0_5() { assert_eq!( FPDecimal::E.pow_robust(FPDecimal::from_str("0.5").unwrap()), - FPDecimal::from_str("1.648721270700128139").unwrap() + // 1.6487212707001281469 + FPDecimal::from_str("1.648721270700128146").unwrap() ); } @@ -1713,64 +2334,57 @@ mod tests { fn test_2_3_pow_1_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("1.4"); - let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); let result_2 = FPDecimal::pow_robust(base, exponent); - assert_eq!(result_2, FPDecimal::must_from_str("3.209363953267971368")); - // 3.209363953267971906 - assert_eq!(result_1, FPDecimal::must_from_str("3.209363953267971924")); + assert_eq!(result_2, FPDecimal::must_from_str("3.209363953267971906")); } #[test] fn test_2_3_pow_3_7() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("3.7"); - let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); let result_2 = FPDecimal::pow_robust(base, exponent); - assert_eq!(result_2, FPDecimal::must_from_str("21.796812747431183828")); - assert_eq!(result_1, FPDecimal::must_from_str("21.796812747431110477")); + //21.796812747431183828 + assert_eq!(result_2, FPDecimal::must_from_str("21.796812747431186181")); } #[test] fn test_2_3_pow_neg_1_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-1.4"); - let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); let result_2 = FPDecimal::pow_robust(base, exponent); - assert_eq!(result_2, FPDecimal::must_from_str("0.311588219522980128")); - assert_eq!(result_1, FPDecimal::must_from_str("0.311588219522980069")); + // 0.31158821952298012815 + assert_eq!(result_2, FPDecimal::must_from_str("0.311588219522980075")); + // assert_eq!(result_1, FPDecimal::must_from_str("0.311588219522980069")); } #[test] fn test_2_3_pow_neg_3_7() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-3.7"); - let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); let result_2 = FPDecimal::pow_robust(base, exponent); - assert_eq!(result_2, FPDecimal::must_from_str("0.045878267230508407")); - assert_eq!(result_1, FPDecimal::must_from_str("0.045878267230507924")); + // 0.045878267230508407006 + assert_eq!(result_2, FPDecimal::must_from_str("0.045878267230508402")); + // assert_eq!(result_1, FPDecimal::must_from_str("0.045878267230507924")); } #[test] fn test_2_3_pow_0_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("0.4"); - let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); let result_2 = FPDecimal::pow_robust(base, exponent); - assert_eq!(result_2, FPDecimal::must_from_str("1.395375631855639962")); - assert_eq!(result_1, FPDecimal::must_from_str("1.395375631855639967")); + assert_eq!(result_2, FPDecimal::must_from_str("1.395375631855639968")); } #[test] fn test_2_3_pow_neg_0_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-0.4"); - let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); let result_2 = FPDecimal::pow_robust(base, exponent); - //assert_eq!(result_2, FPDecimal::must_from_str("0.716652904902854162")); - assert_eq!(result_2, FPDecimal::must_from_str("0.716652904902854173")); - - //assert_eq!(result, FPDecimal::must_from_str("0.716652904985255325")); - assert_eq!(result, FPDecimal::must_from_str("0.716652904902854162")); + // 0.71665290490285417314 + assert_eq!(result_2, FPDecimal::must_from_str("0.716652904902854170")); } #[test] @@ -1808,11 +2422,9 @@ mod tests { } #[test] + #[should_panic] fn test_neg_1000_pow_1_over_3() { - assert_eq!( - FPDecimal::pow_robust(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::THREE), - -FPDecimal::TEN - ); + FPDecimal::pow_robust(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::THREE); } #[test] @@ -1823,6 +2435,20 @@ mod tests { ); } + #[test] + fn test_neg_10_pow_4() { + assert_eq!( + FPDecimal::pow_robust(FPDecimal::must_from_str("-10"), FPDecimal::FOUR), + FPDecimal::TEN.pow_robust(FPDecimal::FOUR) + ); + } + + #[test] + #[should_panic] + fn test_neg_10_pow_2_3() { + FPDecimal::pow_robust(FPDecimal::must_from_str("-10"), FPDecimal::must_from_str("2.3")); + } + #[test] #[should_panic] fn test_neg_1000_pow_1_over_4() { @@ -1838,6 +2464,15 @@ mod tests { assert_eq!(FPDecimal::E.pow_robust(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); } + #[test] + fn test_sqrt() { + assert_eq!(FPDecimal::FOUR.sqrt(), FPDecimal::TWO); + assert_eq!(FPDecimal::from(16u128).sqrt(), FPDecimal::FOUR); + assert_eq!(FPDecimal::ONE.sqrt(), FPDecimal::ONE); + assert_eq!(FPDecimal::NINE.sqrt(), FPDecimal::THREE); + assert_eq!(FPDecimal::from(81u128).sqrt(), FPDecimal::NINE); + } + // NOTE: its ok we ignore these two unit tests. they should not be the goal of this crate /* #[test] From 16d3426ec30deea216d77e5a94bca5417b6796f7 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 25 Oct 2023 12:26:27 -0400 Subject: [PATCH 11/26] wip --- packages/injective-math/src/fp_decimal/exp.rs | 14 +++++++++++--- .../injective-math/src/fp_decimal/trigonometry.rs | 6 ++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index a4e0e793..47b372dc 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -74,6 +74,10 @@ impl FPDecimal { return self.sqrt(); } fn common_const_checks(base: FPDecimal, exponent: FPDecimal) -> Option { + if base == FPDecimal::ONE { + return Some(FPDecimal::ONE); + } + if base == FPDecimal::E { if exponent == FPDecimal::ONE { return Some(base); @@ -691,7 +695,6 @@ impl FPDecimal { type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); - // println!("i'm here {}", exponent); match common_checks(exponent) { Some(value) => { return value; @@ -710,8 +713,6 @@ impl FPDecimal { if log_fn(exponent).is_some() { let value = log_fn(exponent).unwrap(); if self == divisor { - println!("i'm here {}**{}", self, exponent); - return value; } } @@ -2472,6 +2473,13 @@ mod tests { assert_eq!(FPDecimal::NINE.sqrt(), FPDecimal::THREE); assert_eq!(FPDecimal::from(81u128).sqrt(), FPDecimal::NINE); } + #[test] + fn test_1_power_n() { + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow_robust(FPDecimal::ONE)); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow_robust(FPDecimal::TWO)); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow_robust(FPDecimal::THREE)); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow_robust(FPDecimal::FOUR)); + } // NOTE: its ok we ignore these two unit tests. they should not be the goal of this crate /* diff --git a/packages/injective-math/src/fp_decimal/trigonometry.rs b/packages/injective-math/src/fp_decimal/trigonometry.rs index 95780428..e1574d01 100644 --- a/packages/injective-math/src/fp_decimal/trigonometry.rs +++ b/packages/injective-math/src/fp_decimal/trigonometry.rs @@ -113,14 +113,12 @@ mod tests { #[test] fn test_sine_one() { + //0.84147098480789650666 almost_eq(FPDecimal::ONE.imprecise_sin(), FPDecimal::from_str("0.8414709848").unwrap()); } #[test] fn test_sine_negative_one() { - almost_eq( - (FPDecimal::ZERO - FPDecimal::ONE).imprecise_sin(), - FPDecimal::from_str("-0.8414709848").unwrap(), - ); + almost_eq((-FPDecimal::ONE).imprecise_sin(), FPDecimal::from_str("-0.8414709848").unwrap()); } } From 83320ec87c032ec8f66c092c9543ccdd1facd39d Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 25 Oct 2023 12:37:58 -0400 Subject: [PATCH 12/26] fixed lint --- Cargo.lock | 6 +- packages/injective-math/Cargo.toml | 3 +- .../src/fp_decimal/arithmetic.rs | 6 +- packages/injective-math/src/fp_decimal/exp.rs | 141 ++++++++---------- .../injective-math/src/fp_decimal/from_str.rs | 7 +- packages/injective-math/src/fp_decimal/log.rs | 4 +- .../injective-math/src/fp_decimal/scale.rs | 2 +- .../src/fp_decimal/trigonometry.rs | 10 +- 8 files changed, 76 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f516c43..021311d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -945,7 +945,7 @@ dependencies = [ "cw-storage-plus 0.15.1", "ethereum-types", "hex", - "injective-math 0.1.23", + "injective-math 0.1.24", "schemars", "serde 1.0.188", "serde-json-wasm 0.4.1", @@ -972,7 +972,7 @@ dependencies = [ [[package]] name = "injective-math" -version = "0.1.23" +version = "0.1.24" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -1021,7 +1021,7 @@ dependencies = [ "cosmwasm-std", "cw-multi-test", "injective-cosmwasm 0.2.14", - "injective-math 0.1.23", + "injective-math 0.1.24", "rand 0.4.6", "secp256k1", "serde 1.0.188", diff --git a/packages/injective-math/Cargo.toml b/packages/injective-math/Cargo.toml index a45ebf51..98f7ab4f 100644 --- a/packages/injective-math/Cargo.toml +++ b/packages/injective-math/Cargo.toml @@ -6,7 +6,7 @@ license = "Apache-2.0" name = "injective-math" readme = "README.md" repository = "https://github.com/InjectiveLabs/cw-injective/tree/master/packages/injective-math" -version = "0.1.23" +version = "0.1.24" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -21,7 +21,6 @@ ethereum-types = "0.5.2" schemars = "0.8.8" serde = { version = "1.0.136", default-features = false, features = [ "derive" ] } subtle-encoding = { version = "0.5.1", features = [ "bech32-preview" ] } -#num-traits = "0.2.17" [dev-dependencies] cosmwasm-schema = { version = "1.4.1" } diff --git a/packages/injective-math/src/fp_decimal/arithmetic.rs b/packages/injective-math/src/fp_decimal/arithmetic.rs index 5693d878..3f382790 100644 --- a/packages/injective-math/src/fp_decimal/arithmetic.rs +++ b/packages/injective-math/src/fp_decimal/arithmetic.rs @@ -63,9 +63,9 @@ impl FPDecimal { let x2y2 = x2 * y2; let mut result = x1y1; - result = result + x2y1; - result = result + x1y2; - result = result + x2y2 / FPDecimal::MUL_PRECISION.num / FPDecimal::MUL_PRECISION.num; + result += x2y1; + result += x1y2; + result += x2y2 / FPDecimal::MUL_PRECISION.num / FPDecimal::MUL_PRECISION.num; FPDecimal { num: result, sign } } diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 47b372dc..6872d1d9 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -55,14 +55,7 @@ impl FPDecimal { } // e^(a) - // pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { - // if self < FPDecimal::ZERO && exponent.is_int() && exponent % FPDecimal::TWO == FPDecimal::ONE { - // return -FPDecimal::exp(exponent * (-self).ln()); - // } - // self._pow_robust(exponent) - // } - - pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { + pub fn pow(self, exponent: FPDecimal) -> FPDecimal { if self.is_zero() { return self; } @@ -696,9 +689,7 @@ impl FPDecimal { type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); match common_checks(exponent) { - Some(value) => { - return value; - } + Some(value) => value, None => { let base_checks: Vec = vec![ (&FPDecimal::_log_e, FPDecimal::E), @@ -739,7 +730,7 @@ impl FPDecimal { let mut x = a.num; let mut r = FPDecimal::ONE; while x >= U256([10, 0, 0, 0]) * FPDecimal::ONE.num { - x = x - U256([10, 0, 0, 0]) * FPDecimal::ONE.num; + x -= U256([10, 0, 0, 0]) * FPDecimal::ONE.num; r = FPDecimal::_mul(r, FPDecimal::E_10); } if x == FPDecimal::ONE.num { @@ -759,7 +750,7 @@ impl FPDecimal { let mut d = tr; for i in 1..((2 * FPDecimal::DIGITS + 1) as u64) { d = (d * x) / (FPDecimal::ONE.num * U256([i, 0, 0, 0])); - tr = tr + d; + tr += d; } let val = FPDecimal::_mul(FPDecimal { num: tr, sign: 1 }, r); if a.sign == 0 { @@ -2041,19 +2032,19 @@ mod tests { #[test] fn test_pow_zero() { - FPDecimal::pow_robust(FPDecimal::ZERO, FPDecimal::ONE.div(2i128)); - assert_eq!(FPDecimal::ZERO.pow_robust(FPDecimal::ONE), FPDecimal::ZERO); + FPDecimal::pow(FPDecimal::ZERO, FPDecimal::ONE.div(2i128)); + assert_eq!(FPDecimal::ZERO.pow(FPDecimal::ONE), FPDecimal::ZERO); } #[test] fn test_4_pow_0_5() { - assert_eq!(FPDecimal::pow_robust(FPDecimal::FOUR, FPDecimal::must_from_str("0.5")), FPDecimal::TWO); + assert_eq!(FPDecimal::pow(FPDecimal::FOUR, FPDecimal::must_from_str("0.5")), FPDecimal::TWO); } #[test] fn test_128_pow_0_5() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(128u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(128u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("11.313708498984760390") ); } @@ -2061,27 +2052,27 @@ mod tests { #[test] fn test_128_pow_1_7() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(128u128), FPDecimal::ONE / FPDecimal::SEVEN), + FPDecimal::pow(FPDecimal::from(128u128), FPDecimal::ONE / FPDecimal::SEVEN), FPDecimal::TWO ); } #[test] fn test_9_pow_0_5() { - assert_eq!(FPDecimal::pow_robust(FPDecimal::NINE, FPDecimal::must_from_str("0.5")), FPDecimal::THREE); + assert_eq!(FPDecimal::pow(FPDecimal::NINE, FPDecimal::must_from_str("0.5")), FPDecimal::THREE); } #[test] fn test_27_pow_0_5() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(27u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(27u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("5.196152422706631880") ); } #[test] fn test_27_pow_1_over_3() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(27u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(27u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::THREE ); } @@ -2089,38 +2080,32 @@ mod tests { #[test] fn test_81_pow_0_25() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::FOUR), FPDecimal::THREE ); } #[test] fn test_81_pow_0_5() { - assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::TWO), - FPDecimal::NINE - ); + assert_eq!(FPDecimal::pow(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::TWO), FPDecimal::NINE); } #[test] fn test_25_pow_0_5() { - assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(25u128), FPDecimal::must_from_str("0.5")), - FPDecimal::FIVE - ); + assert_eq!(FPDecimal::pow(FPDecimal::from(25u128), FPDecimal::must_from_str("0.5")), FPDecimal::FIVE); } #[test] fn test_125_pow_0_5() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(125u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(125u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("11.180339887498948482") ); } #[test] fn test_125_pow_1_over_3() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(125u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(125u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::FIVE ); } @@ -2128,30 +2113,27 @@ mod tests { #[test] fn test_625_pow_0_25() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(625u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::from(625u128), FPDecimal::ONE / FPDecimal::FOUR), FPDecimal::FIVE ); } #[test] fn test_49_pow_0_5() { - assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(49u128), FPDecimal::must_from_str("0.5")), - FPDecimal::SEVEN - ); + assert_eq!(FPDecimal::pow(FPDecimal::from(49u128), FPDecimal::must_from_str("0.5")), FPDecimal::SEVEN); } #[test] fn test_343_pow_0_5() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(343u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(343u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("18.520259177452134133") ); } #[test] fn test_343_pow_1_over_3() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(343u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(343u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::SEVEN ); } @@ -2159,7 +2141,7 @@ mod tests { #[test] fn test_2401_pow_0_25() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(2401u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::from(2401u128), FPDecimal::ONE / FPDecimal::FOUR), FPDecimal::SEVEN ); } @@ -2167,7 +2149,7 @@ mod tests { #[test] fn test_121_pow_0_5() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(121u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(121u128), FPDecimal::must_from_str("0.5")), FPDecimal::from(11u128) ); } @@ -2175,14 +2157,14 @@ mod tests { #[test] fn test_1331_pow_0_5() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(1331u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::must_from_str("0.5")), FPDecimal::must_from_str("36.48287269390939834") ); } #[test] fn test_1331_pow_1_over_3() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(1331u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::from(11u128) ); } @@ -2190,35 +2172,35 @@ mod tests { #[test] fn test_14641_pow_0_25() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(14641u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::from(14641u128), FPDecimal::ONE / FPDecimal::FOUR), FPDecimal::from(11u128) ); } #[test] fn test_2_pow_1() { - assert_eq!(FPDecimal::TWO.pow_robust(FPDecimal::ONE), FPDecimal::TWO); + assert_eq!(FPDecimal::TWO.pow(FPDecimal::ONE), FPDecimal::TWO); } #[test] fn test_3_pow_1() { - assert_eq!(FPDecimal::THREE.pow_robust(FPDecimal::ONE), FPDecimal::THREE); + assert_eq!(FPDecimal::THREE.pow(FPDecimal::ONE), FPDecimal::THREE); } #[test] fn test_pow_exp_1() { - assert_eq!(FPDecimal::E.pow_robust(FPDecimal::ONE), FPDecimal::E); + assert_eq!(FPDecimal::E.pow(FPDecimal::ONE), FPDecimal::E); } #[test] fn test_pow_exp_0() { - assert_eq!(FPDecimal::E.pow_robust(FPDecimal::ZERO), FPDecimal::ONE); + assert_eq!(FPDecimal::E.pow(FPDecimal::ZERO), FPDecimal::ONE); } #[test] fn test_pow_exp_10() { assert_eq!( - FPDecimal::E.pow_robust(FPDecimal { + FPDecimal::E.pow(FPDecimal { num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, sign: 1 }), @@ -2228,7 +2210,7 @@ mod tests { #[test] fn test_pow_zero_2() { - FPDecimal::ZERO.pow_robust(FPDecimal::ONE.div(2i128)); + FPDecimal::ZERO.pow(FPDecimal::ONE.div(2i128)); } #[test] @@ -2262,17 +2244,14 @@ mod tests { #[test] fn test_pow_10_positive() { let base = FPDecimal::from(10u128); - assert_eq!( - base.pow_robust(FPDecimal::from_str("6").unwrap()), - FPDecimal::from_str("1000000").unwrap() - ); + assert_eq!(base.pow(FPDecimal::from_str("6").unwrap()), FPDecimal::from_str("1000000").unwrap()); } #[test] fn test_pow_10_max() { let base = FPDecimal::from(10u128); assert_eq!( - base.pow_robust(FPDecimal::from_str("59").unwrap()), + base.pow(FPDecimal::from_str("59").unwrap()), FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000000").unwrap() ); } @@ -2281,20 +2260,20 @@ mod tests { #[should_panic] fn test_pow_10_overflow() { let base = FPDecimal::from(10u128); - base.pow_robust(FPDecimal::from_str("60").unwrap()); + base.pow(FPDecimal::from_str("60").unwrap()); } #[test] fn test_pow_10_neg_3() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow_robust(FPDecimal::from_str("-3").unwrap()), FPDecimal::from_str("0.001").unwrap()); + assert_eq!(base.pow(FPDecimal::from_str("-3").unwrap()), FPDecimal::from_str("0.001").unwrap()); } #[test] fn test_e_pow_neg_3() { let base = FPDecimal::E; assert_eq!( - base.pow_robust(FPDecimal::from_str("-3").unwrap()), + base.pow(FPDecimal::from_str("-3").unwrap()), FPDecimal::from_str("0.049787068367863943").unwrap() ); } @@ -2302,7 +2281,7 @@ mod tests { #[test] fn test_e_pow_0_5() { assert_eq!( - FPDecimal::E.pow_robust(FPDecimal::from_str("0.5").unwrap()), + FPDecimal::E.pow(FPDecimal::from_str("0.5").unwrap()), // 1.6487212707001281469 FPDecimal::from_str("1.648721270700128146").unwrap() ); @@ -2312,7 +2291,7 @@ mod tests { fn test_pow_10_min() { let base = FPDecimal::from(10u128); assert_eq!( - base.pow_robust(FPDecimal::from_str("-18").unwrap()), + base.pow(FPDecimal::from_str("-18").unwrap()), FPDecimal::from_str("0.000000000000000001").unwrap() ); } @@ -2320,7 +2299,7 @@ mod tests { #[test] fn test_pow_10_underflow() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow_robust(FPDecimal::from_str("-19").unwrap()), FPDecimal::ZERO); + assert_eq!(base.pow(FPDecimal::from_str("-19").unwrap()), FPDecimal::ZERO); } #[test] @@ -2336,7 +2315,7 @@ mod tests { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("1.4"); // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - let result_2 = FPDecimal::pow_robust(base, exponent); + let result_2 = FPDecimal::pow(base, exponent); assert_eq!(result_2, FPDecimal::must_from_str("3.209363953267971906")); } @@ -2344,7 +2323,7 @@ mod tests { fn test_2_3_pow_3_7() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("3.7"); - let result_2 = FPDecimal::pow_robust(base, exponent); + let result_2 = FPDecimal::pow(base, exponent); //21.796812747431183828 assert_eq!(result_2, FPDecimal::must_from_str("21.796812747431186181")); } @@ -2354,7 +2333,7 @@ mod tests { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-1.4"); // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - let result_2 = FPDecimal::pow_robust(base, exponent); + let result_2 = FPDecimal::pow(base, exponent); // 0.31158821952298012815 assert_eq!(result_2, FPDecimal::must_from_str("0.311588219522980075")); // assert_eq!(result_1, FPDecimal::must_from_str("0.311588219522980069")); @@ -2365,7 +2344,7 @@ mod tests { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-3.7"); // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - let result_2 = FPDecimal::pow_robust(base, exponent); + let result_2 = FPDecimal::pow(base, exponent); // 0.045878267230508407006 assert_eq!(result_2, FPDecimal::must_from_str("0.045878267230508402")); // assert_eq!(result_1, FPDecimal::must_from_str("0.045878267230507924")); @@ -2375,7 +2354,7 @@ mod tests { fn test_2_3_pow_0_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("0.4"); - let result_2 = FPDecimal::pow_robust(base, exponent); + let result_2 = FPDecimal::pow(base, exponent); assert_eq!(result_2, FPDecimal::must_from_str("1.395375631855639968")); } @@ -2383,7 +2362,7 @@ mod tests { fn test_2_3_pow_neg_0_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-0.4"); - let result_2 = FPDecimal::pow_robust(base, exponent); + let result_2 = FPDecimal::pow(base, exponent); // 0.71665290490285417314 assert_eq!(result_2, FPDecimal::must_from_str("0.716652904902854170")); } @@ -2409,7 +2388,7 @@ mod tests { #[test] fn test_100_pow_neg_1_over_2() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(100u128), FPDecimal::must_from_str("-0.5")), + FPDecimal::pow(FPDecimal::from(100u128), FPDecimal::must_from_str("-0.5")), FPDecimal::must_from_str("0.1") ); } @@ -2417,7 +2396,7 @@ mod tests { #[test] fn test_1000_pow_1_over_3() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::from(1000u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(1000u128), FPDecimal::ONE / FPDecimal::THREE), FPDecimal::TEN ); } @@ -2425,36 +2404,36 @@ mod tests { #[test] #[should_panic] fn test_neg_1000_pow_1_over_3() { - FPDecimal::pow_robust(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::THREE); + FPDecimal::pow(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::THREE); } #[test] fn test_neg_10_pow_3() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::must_from_str("-10"), FPDecimal::THREE), - -FPDecimal::TEN.pow_robust(FPDecimal::THREE) + FPDecimal::pow(FPDecimal::must_from_str("-10"), FPDecimal::THREE), + -FPDecimal::TEN.pow(FPDecimal::THREE) ); } #[test] fn test_neg_10_pow_4() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::must_from_str("-10"), FPDecimal::FOUR), - FPDecimal::TEN.pow_robust(FPDecimal::FOUR) + FPDecimal::pow(FPDecimal::must_from_str("-10"), FPDecimal::FOUR), + FPDecimal::TEN.pow(FPDecimal::FOUR) ); } #[test] #[should_panic] fn test_neg_10_pow_2_3() { - FPDecimal::pow_robust(FPDecimal::must_from_str("-10"), FPDecimal::must_from_str("2.3")); + FPDecimal::pow(FPDecimal::must_from_str("-10"), FPDecimal::must_from_str("2.3")); } #[test] #[should_panic] fn test_neg_1000_pow_1_over_4() { assert_eq!( - FPDecimal::pow_robust(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::FOUR), -FPDecimal::TEN ); } @@ -2462,7 +2441,7 @@ mod tests { #[test] fn test_exp_log_2() { // assert_eq!(FPDecimal::E.pow(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); - assert_eq!(FPDecimal::E.pow_robust(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); + assert_eq!(FPDecimal::E.pow(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); } #[test] @@ -2475,10 +2454,10 @@ mod tests { } #[test] fn test_1_power_n() { - assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow_robust(FPDecimal::ONE)); - assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow_robust(FPDecimal::TWO)); - assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow_robust(FPDecimal::THREE)); - assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow_robust(FPDecimal::FOUR)); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::ONE)); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::TWO)); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::THREE)); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::FOUR)); } // NOTE: its ok we ignore these two unit tests. they should not be the goal of this crate diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs index 3d5adca1..ecf5a223 100644 --- a/packages/injective-math/src/fp_decimal/from_str.rs +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -45,12 +45,7 @@ impl FromStr for FPDecimal { impl FPDecimal { pub fn must_from_str(input: &str) -> Self { - let i = Self::from_str(input).unwrap(); - // to handle must_from_str("-0") - //if i.num == U256([0, 0, 0, 0]) { - // return FPDecimal::ZERO; - //} - i + Self::from_str(input).unwrap() } } diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 93fef031..529c4bee 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -567,11 +567,11 @@ impl FPDecimal { let mut v = self.num; let mut r = FPDecimal::ZERO; while v <= FPDecimal::ONE.num / U256([10, 0, 0, 0]) { - v = v * U256([10, 0, 0, 0]); + v *= U256([10, 0, 0, 0]); r -= FPDecimal::LN_10; } while v >= U256([10, 0, 0, 0]) * FPDecimal::ONE.num { - v = v / U256([10, 0, 0, 0]); + v /= U256([10, 0, 0, 0]); r += FPDecimal::LN_10; } while v < FPDecimal::ONE.num { diff --git a/packages/injective-math/src/fp_decimal/scale.rs b/packages/injective-math/src/fp_decimal/scale.rs index 0cf199c9..e72196f4 100644 --- a/packages/injective-math/src/fp_decimal/scale.rs +++ b/packages/injective-math/src/fp_decimal/scale.rs @@ -6,7 +6,7 @@ pub trait Scaled { impl Scaled for FPDecimal { fn scaled(self, digits: i32) -> Self { - self.to_owned() * FPDecimal::from(10i128).pow_robust(FPDecimal::from(digits as i128)) + self.to_owned() * FPDecimal::from(10i128).pow(FPDecimal::from(digits as i128)) } } diff --git a/packages/injective-math/src/fp_decimal/trigonometry.rs b/packages/injective-math/src/fp_decimal/trigonometry.rs index e1574d01..32f53134 100644 --- a/packages/injective-math/src/fp_decimal/trigonometry.rs +++ b/packages/injective-math/src/fp_decimal/trigonometry.rs @@ -7,11 +7,11 @@ impl FPDecimal { } fn _sine_taylor_expansion(x: FPDecimal) -> FPDecimal { - x - (x.pow_robust(FPDecimal::THREE) / FPDecimal::THREE.factorial()) + (x.pow_robust(FPDecimal::FIVE) / FPDecimal::FIVE.factorial()) - - (x.pow_robust(FPDecimal::SEVEN) / FPDecimal::SEVEN.factorial()) - + (x.pow_robust(FPDecimal::NINE) / FPDecimal::NINE.factorial()) - - (x.pow_robust(FPDecimal::TWO + FPDecimal::NINE) / (FPDecimal::TWO + FPDecimal::NINE).factorial()) - + (x.pow_robust(FPDecimal::FOUR + FPDecimal::NINE) / (FPDecimal::FOUR + FPDecimal::NINE).factorial()) + x - (x.pow(FPDecimal::THREE) / FPDecimal::THREE.factorial()) + (x.pow(FPDecimal::FIVE) / FPDecimal::FIVE.factorial()) + - (x.pow(FPDecimal::SEVEN) / FPDecimal::SEVEN.factorial()) + + (x.pow(FPDecimal::NINE) / FPDecimal::NINE.factorial()) + - (x.pow(FPDecimal::TWO + FPDecimal::NINE) / (FPDecimal::TWO + FPDecimal::NINE).factorial()) + + (x.pow(FPDecimal::FOUR + FPDecimal::NINE) / (FPDecimal::FOUR + FPDecimal::NINE).factorial()) } pub fn _sin(mut x: FPDecimal) -> FPDecimal { From 4a6caddfe6411ab35e7a1f02f2ed59ea2796e790 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 25 Oct 2023 12:48:45 -0400 Subject: [PATCH 13/26] wip --- packages/injective-math/src/fp_decimal/exp.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 6872d1d9..3147e3cc 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -660,10 +660,6 @@ impl FPDecimal { } } - if let Some(value) = common_const_checks(self, exponent) { - return value; - } - fn common_checks(exponent: FPDecimal) -> Option { if FPDecimal::TWO.ln() == exponent { return Some(FPDecimal::TWO); @@ -688,6 +684,10 @@ impl FPDecimal { type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); + if let Some(value) = common_const_checks(self, exponent) { + return value; + } + match common_checks(exponent) { Some(value) => value, None => { From 576b86d1c4645ffd0ef93efc25aa91ae9a525d6a Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 25 Oct 2023 18:05:57 -0400 Subject: [PATCH 14/26] added newton, discrete newton --- packages/injective-math/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/injective-math/src/lib.rs b/packages/injective-math/src/lib.rs index 54da30c7..68ff5232 100644 --- a/packages/injective-math/src/lib.rs +++ b/packages/injective-math/src/lib.rs @@ -1,9 +1,11 @@ pub mod fp_decimal; +pub mod root_findings; pub mod utils; pub mod vector; use cosmwasm_std::{StdResult, Uint128}; pub use fp_decimal::*; +pub use root_findings::*; use std::str::FromStr; pub use utils::*; pub use vector::*; From a36dde2eeca695781bc73719f984a1a1fb4bb0a1 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Thu, 26 Oct 2023 12:03:46 -0400 Subject: [PATCH 15/26] added newton, discrete newon, halley methods --- packages/injective-math/src/root_findings.rs | 234 +++++++++++++++++++ packages/injective-math/src/utils.rs | 3 + 2 files changed, 237 insertions(+) create mode 100644 packages/injective-math/src/root_findings.rs diff --git a/packages/injective-math/src/root_findings.rs b/packages/injective-math/src/root_findings.rs new file mode 100644 index 00000000..a46a901f --- /dev/null +++ b/packages/injective-math/src/root_findings.rs @@ -0,0 +1,234 @@ +use crate::fp_decimal::FPDecimal; +use crate::utils::round; + +pub fn newton(f: Func, fd: DFunc, mut x0: FPDecimal, abs_error: FPDecimal, max_iter: usize) -> Result +where + Func: Fn(FPDecimal) -> FPDecimal, + DFunc: Fn(FPDecimal) -> FPDecimal, +{ + // WARN: No complex number support + let mut x1 = x0; + for _ in 0..max_iter { + x0 -= f(x1) / fd(x1); + if (x0 - x1).abs() < abs_error { + return Ok(x0); + } + x1 = x0; + } + Err(x0) +} + +pub fn discrete_newton( + func: Func, + delta: FPDecimal, + x0: FPDecimal, + obj: FPDecimal, + abs_error: FPDecimal, + max_iter: usize, +) -> Result +where + Func: Fn(FPDecimal) -> FPDecimal, +{ + //https://www.mathworks.com/matlabcentral/fileexchange/68170-discrete-newton-newton-s-method-for-discrete-functions + // WARN: No complex number support + let y0 = func(x0); + let mut xn = x0; + let mut yn = y0; + + let x1 = x0 + delta; + let y1 = func(x1); + + let mut m = (y1 - y0) / (x1 - x0); + + let mut xr; + let mut yr; + let mut mr; + + let mut xl; + let mut yl; + let mut ml; + + let mut dx; + + for _ in 0..max_iter { + dx = (obj - yn) / m; + dx = delta * round(dx / delta, FPDecimal::ONE); + + let xk = xn; + xn += dx; + // let yk = yn; + yn = func(xn); + + if xk != xn { + xr = xn + delta; + xl = xn - delta; + + yr = func(xr); + yl = func(xl); + + mr = (yr - yn) / delta; + ml = (yn - yl) / delta; + + m = (mr + ml) / FPDecimal::TWO; + } else { + return Ok(round(xn, abs_error)); + } + } + Err(round(xn, abs_error)) +} + +#[allow(dead_code)] +fn halleys( + f: Func, + fd: DFunc, + fdd: DDFunc, + mut x0: FPDecimal, + abs_error: FPDecimal, + max_iter: usize, +) -> Result +where + Func: Fn(FPDecimal) -> FPDecimal, + DFunc: Fn(FPDecimal) -> FPDecimal, + DDFunc: Fn(FPDecimal) -> FPDecimal, +{ + let mut x1 = x0; + for _ in 0..max_iter { + let fxn = f(x1); + let dfxn = fd(x1); + let ddfxn = fdd(x1); + x0 -= FPDecimal::TWO * (fxn * dfxn) / (FPDecimal::TWO * dfxn * dfxn - fxn * ddfxn); + if (x0 - x1).abs() < abs_error { + return Ok(x0); + } + x1 = x0; + } + Err(x0) +} + +// TODO: add a discrete halley's method + +#[cfg(test)] +mod tests { + use crate::root_findings::*; + use crate::FPDecimal; + + #[test] + fn test_discrete_newton_1() { + let x0 = FPDecimal::ONE; + fn func(x0: FPDecimal) -> FPDecimal { + x0.ln() + } + let delta = FPDecimal::ONE; + let obj = FPDecimal::must_from_str("3.23"); + let max_iter = 300; + let abs_error = FPDecimal::ONE; + let output = discrete_newton(func, delta, x0, obj, abs_error, max_iter).unwrap(); + let target = FPDecimal::must_from_str("25"); + assert_eq!(output, target); + } + + #[test] + fn test_discrete_newton_2() { + let x0 = FPDecimal::TEN; + fn func(x0: FPDecimal) -> FPDecimal { + x0.pow(FPDecimal::TWO) + } + let delta = FPDecimal::must_from_str("0.25"); + let obj = FPDecimal::FIVE; + let max_iter = 300; + let abs_error = FPDecimal::must_from_str("0.01"); + let output = discrete_newton(func, delta, x0, obj, abs_error, max_iter).unwrap(); + let target = FPDecimal::must_from_str("2.25"); + assert_eq!(output, target); + } + + #[test] + fn test_discrete_newton_3() { + let x0 = FPDecimal::TEN; + fn func(x0: FPDecimal) -> FPDecimal { + -x0.pow(FPDecimal::TWO) + FPDecimal::TWO * x0 - FPDecimal::ONE + } + let delta = FPDecimal::ONE / FPDecimal::THREE; + let obj = FPDecimal::must_from_str("-15"); + let max_iter = 300; + let abs_error = FPDecimal::ONE; + let output = discrete_newton(func, delta, x0, obj, abs_error, max_iter).unwrap(); + let target = FPDecimal::FIVE; + assert_eq!(output, target); + } + + #[test] + fn test_newton_1() { + fn f(x0: FPDecimal) -> FPDecimal { + // x0 * x0 * FPDecimal::THREE + x0 * x0 * x0 - x0 * x0 - FPDecimal::ONE + } + fn fd(x0: FPDecimal) -> FPDecimal { + // FPDecimal::SIX * x0 + FPDecimal::THREE * x0 * x0 - FPDecimal::TWO * x0 + } + let x0 = FPDecimal::ONE; + let max_iter = 30; + let abs_error = FPDecimal::must_from_str("0.00000000001"); + let target = FPDecimal::must_from_str("1.465571231876768027"); + let output = newton(f, fd, x0, abs_error, max_iter).unwrap(); + assert_eq!(output, target); + } + + #[test] + fn test_newton_2() { + fn f(x0: FPDecimal) -> FPDecimal { + x0 * x0 * x0 - x0 * x0 + FPDecimal::TWO + } + fn fd(x0: FPDecimal) -> FPDecimal { + FPDecimal::THREE * x0 * x0 - FPDecimal::TWO * x0 + } + let x0 = -FPDecimal::must_from_str("20"); + let max_iter = 30; + let abs_error = FPDecimal::must_from_str("0.00000000001"); + let target = -FPDecimal::ONE; + let output = newton(f, fd, x0, abs_error, max_iter).unwrap(); + assert_eq!(round(output, FPDecimal::must_from_str("0.0001")), target); + } + + #[test] + fn test_halleys_1() { + fn f(x0: FPDecimal) -> FPDecimal { + x0 * x0 * x0 - x0 * x0 + FPDecimal::TWO + } + fn fd(x0: FPDecimal) -> FPDecimal { + FPDecimal::THREE * x0 * x0 - FPDecimal::TWO * x0 + } + fn fdd(x0: FPDecimal) -> FPDecimal { + FPDecimal::SIX * x0 - FPDecimal::TWO + } + let x0 = -FPDecimal::must_from_str("20"); + let max_iter = 30; + let abs_error = FPDecimal::must_from_str("0.00000000001"); + let target = -FPDecimal::ONE; + let output = halleys(f, fd, fdd, x0, abs_error, max_iter).unwrap(); + assert_eq!(round(output, FPDecimal::must_from_str("0.0001")), target); + } + + #[test] + fn test_halleys_2() { + fn f(x0: FPDecimal) -> FPDecimal { + // x0 * x0 * FPDecimal::THREE + x0 * x0 * x0 - x0 * x0 - FPDecimal::ONE + } + fn fd(x0: FPDecimal) -> FPDecimal { + // FPDecimal::SIX * x0 + FPDecimal::THREE * x0 * x0 - FPDecimal::TWO * x0 + } + fn fdd(x0: FPDecimal) -> FPDecimal { + FPDecimal::SIX * x0 - FPDecimal::TWO + } + + let x0 = FPDecimal::ONE; + let max_iter = 30; + let abs_error = FPDecimal::must_from_str("0.00000000001"); + let target = FPDecimal::must_from_str("1.465571231876768026"); + let output = halleys(f, fd, fdd, x0, abs_error, max_iter).unwrap(); + assert_eq!(output, target); + } +} diff --git a/packages/injective-math/src/utils.rs b/packages/injective-math/src/utils.rs index cba94ba4..53060d3e 100644 --- a/packages/injective-math/src/utils.rs +++ b/packages/injective-math/src/utils.rs @@ -88,6 +88,9 @@ pub fn floor(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { } pub fn round(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { + if min_tick < FPDecimal::must_from_str("0.00000001") { + panic!("min_tick should be greater than {}", FPDecimal::must_from_str("0.00000001")); + } let num_floor = floor(num, min_tick); let diff = num - num_floor; match diff.cmp(&(min_tick / FPDecimal::TWO)) { From 1da69d936392638b49b310e31d25db6d6d29946b Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Thu, 26 Oct 2023 12:16:02 -0400 Subject: [PATCH 16/26] cleaned up comments --- packages/injective-math/src/fp_decimal/exp.rs | 95 +------------------ 1 file changed, 2 insertions(+), 93 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 3147e3cc..60827e9e 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -759,46 +759,6 @@ impl FPDecimal { val } - // pub fn _exp(a: FPDecimal) -> FPDecimal { - // // this throws underflow with a sufficiently large negative exponent - // // short circuit and just return 0 above a certain threshold - // // otherwise if there is a long enough delay between updates on a cluster - // // the penalty function will be bricked - // if a.sign == 0 && a.num >= FPDecimal::from(45i128).num { - // return FPDecimal::ZERO; - // } - // let mut x = a.num; - // let mut r = FPDecimal::ONE; - // while x >= U256([10, 0, 0, 0]) * FPDecimal::ONE.num { - // x = x - U256([10, 0, 0, 0]) * FPDecimal::ONE.num; - // r = FPDecimal::_mul(r, FPDecimal::E_10); - // } - // if x == FPDecimal::ONE.num { - // let val = FPDecimal::_mul(r, FPDecimal::E); - // if a.sign == 0 { - // return FPDecimal::reciprocal(val); - // } - // return val; - // } else if x == FPDecimal::ZERO.num { - // let val = r; - // if a.sign == 0 { - // return FPDecimal::reciprocal(val); - // } - // return val; - // } - // let mut tr = FPDecimal::ONE.num; - // let mut d = tr; - // for i in 1..((2 * FPDecimal::DIGITS + 1) as u64) { - // d = (d * x) / (FPDecimal::ONE.num * U256([i, 0, 0, 0])); - // tr = tr + d; - // } - // let val = FPDecimal::_mul(FPDecimal { num: tr, sign: 1 }, r); - // if a.sign == 0 { - // return FPDecimal::reciprocal(val); - // } - // val - // } - // a^(0.5) pub fn _sqrt(a: FPDecimal) -> Option { const MAX_ITERATIONS: i64 = 300; @@ -1824,57 +1784,6 @@ impl FPDecimal { }) } } - // pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { - // // TODO: need to handle e^k seperately, since _Exp function is already implemented - // if self == FPDecimal::E { - // return FPDecimal::exp(exponent); - // } - // if self.is_zero() { - // return self; - // } - // if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { - // return FPDecimal::ONE; - // } - - // // FPDecimal::_pow_robust(self, exponent) - // if self >= FPDecimal::ZERO { - // match self.checked_positive_pow(exponent) { - // Ok(value) => value, - // Err(_) => panic!("Multiplication overflow"), - // } - // } else { - // match self.checked_negative_pow(exponent) { - // Ok(value) => value, - // Err(_) => panic!("Multiplication overflow"), - // } - // } - // } - - // pub fn pow_robust(self, exponent: FPDecimal) -> FPDecimal { - // // TODO: need to handle e^k seperately, since _Exp function is already implemented - // if self == FPDecimal::E { - // return FPDecimal::exp(exponent); - // } - // if self.is_zero() { - // return self; - // } - // if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { - // return FPDecimal::ONE; - // } - - // // FPDecimal::_pow_robust(self, exponent) - // if self >= FPDecimal::ZERO { - // match self.checked_positive_pow(exponent) { - // Ok(value) => value, - // Err(_) => panic!("Multiplication overflow"), - // } - // } else { - // match self.checked_negative_pow(exponent) { - // Ok(value) => value, - // Err(_) => panic!("Multiplication overflow"), - // } - // } - // } } #[cfg(test)] @@ -2466,7 +2375,7 @@ mod tests { fn test_25_pow_0_11111() { let power = FPDecimal::ONE / FPDecimal::from(9_u128); let result: FPDecimal = FPDecimal::must_from_str("25.0").ln() * power; - let dampen: FPDecimal = FPDecimal::E.pow_robust(result); + let dampen: FPDecimal = FPDecimal::E.pow(result); // 1.4299640339921836144 assert_eq!(dampen, FPDecimal::must_from_str("1.429969148308728731")); } @@ -2474,7 +2383,7 @@ mod tests { fn test_25_pow_0_11111_decimal_lib() { let x = FPDecimal::ONE / FPDecimal::from(9_u128); let a: FPDecimal = FPDecimal::must_from_str("25.0"); - let result: FPDecimal = a.pow_robust(x); + let result: FPDecimal = a.pow(x); assert_eq!(result, FPDecimal::must_from_str("1.429969148308728731")); } */ From 57ee5f58a92a72b6ca1edf682fbdc7abc3f8ba05 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Thu, 26 Oct 2023 12:27:56 -0400 Subject: [PATCH 17/26] bumped version to 0.2.0 --- Cargo.lock | 6 +++--- packages/injective-cosmwasm/Cargo.toml | 2 +- packages/injective-math/Cargo.toml | 2 +- packages/injective-math/src/fp_decimal/arithmetic.rs | 1 - packages/injective-testing/Cargo.toml | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 021311d1..ff5b3046 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -945,7 +945,7 @@ dependencies = [ "cw-storage-plus 0.15.1", "ethereum-types", "hex", - "injective-math 0.1.24", + "injective-math 0.2.0", "schemars", "serde 1.0.188", "serde-json-wasm 0.4.1", @@ -972,7 +972,7 @@ dependencies = [ [[package]] name = "injective-math" -version = "0.1.24" +version = "0.2.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -1021,7 +1021,7 @@ dependencies = [ "cosmwasm-std", "cw-multi-test", "injective-cosmwasm 0.2.14", - "injective-math 0.1.24", + "injective-math 0.2.0", "rand 0.4.6", "secp256k1", "serde 1.0.188", diff --git a/packages/injective-cosmwasm/Cargo.toml b/packages/injective-cosmwasm/Cargo.toml index dd597b19..2b36e22c 100644 --- a/packages/injective-cosmwasm/Cargo.toml +++ b/packages/injective-cosmwasm/Cargo.toml @@ -19,7 +19,7 @@ cosmwasm-std = { version = "1.4.1" } cw-storage-plus = { version = "0.15.0" } ethereum-types = "0.5.2" hex = { version = "0.4.3", features = [ "serde" ] } -injective-math = { path = "../injective-math", version = "0.1.4" } +injective-math = { path = "../injective-math", version = "0.2.0" } schemars = "0.8.8" serde = { version = "1.0.136", default-features = false, features = [ "derive" ] } serde_repr = "0.1" diff --git a/packages/injective-math/Cargo.toml b/packages/injective-math/Cargo.toml index 98f7ab4f..a010fdde 100644 --- a/packages/injective-math/Cargo.toml +++ b/packages/injective-math/Cargo.toml @@ -6,7 +6,7 @@ license = "Apache-2.0" name = "injective-math" readme = "README.md" repository = "https://github.com/InjectiveLabs/cw-injective/tree/master/packages/injective-math" -version = "0.1.24" +version = "0.2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/injective-math/src/fp_decimal/arithmetic.rs b/packages/injective-math/src/fp_decimal/arithmetic.rs index 3f382790..54422fee 100644 --- a/packages/injective-math/src/fp_decimal/arithmetic.rs +++ b/packages/injective-math/src/fp_decimal/arithmetic.rs @@ -88,7 +88,6 @@ impl FPDecimal { FPDecimal { num: U256::try_from(num).unwrap(), - //num: num.into(), sign: 1 ^ x.sign ^ y.sign, } } diff --git a/packages/injective-testing/Cargo.toml b/packages/injective-testing/Cargo.toml index 62f658fb..136519cf 100644 --- a/packages/injective-testing/Cargo.toml +++ b/packages/injective-testing/Cargo.toml @@ -13,7 +13,7 @@ base64 = "0.13.1" cosmwasm-std = { version = "1.4.1", features = [ "abort", "iterator" ] } cw-multi-test = "0.16.2" injective-cosmwasm = { version = "0.2.0", path = "../injective-cosmwasm" } -injective-math = { version = "0.1.17", path = "../injective-math" } +injective-math = { version = "0.2.0", path = "../injective-math" } rand = "0.4.6" secp256k1 = "0.6.2" serde = { version = "1.0.103", default-features = false, features = [ "derive" ] } From 84c4bd00fdb97c05afb1847bc77045f7b58fe457 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Thu, 26 Oct 2023 16:57:52 -0400 Subject: [PATCH 18/26] improved visibility --- .../src/fp_decimal/arithmetic.rs | 8 +- packages/injective-math/src/fp_decimal/exp.rs | 1067 +---------------- .../injective-math/src/fp_decimal/from_str.rs | 1 - .../injective-math/src/fp_decimal/hyper.rs | 6 +- packages/injective-math/src/fp_decimal/log.rs | 60 +- packages/injective-math/src/fp_decimal/mod.rs | 5 + .../src/fp_decimal/trigonometry.rs | 4 +- 7 files changed, 76 insertions(+), 1075 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/arithmetic.rs b/packages/injective-math/src/fp_decimal/arithmetic.rs index 54422fee..28acd585 100644 --- a/packages/injective-math/src/fp_decimal/arithmetic.rs +++ b/packages/injective-math/src/fp_decimal/arithmetic.rs @@ -6,7 +6,7 @@ use std::iter; use std::ops; impl FPDecimal { - pub fn _add(x: FPDecimal, y: FPDecimal) -> FPDecimal { + pub(crate) fn _add(x: FPDecimal, y: FPDecimal) -> FPDecimal { if x.sign == y.sign { return FPDecimal { num: x.num + y.num, @@ -34,7 +34,7 @@ impl FPDecimal { FPDecimal::_add(*self, FPDecimal::from(other)) } - pub fn _sub(x: FPDecimal, y: FPDecimal) -> FPDecimal { + pub(crate) fn _sub(x: FPDecimal, y: FPDecimal) -> FPDecimal { let neg_y = FPDecimal { num: y.num, sign: 1 - y.sign, @@ -46,7 +46,7 @@ impl FPDecimal { FPDecimal::_sub(*self, FPDecimal::from(other)) } - pub fn _mul(x: FPDecimal, y: FPDecimal) -> FPDecimal { + pub(crate) fn _mul(x: FPDecimal, y: FPDecimal) -> FPDecimal { let mut sign = 1; if x.sign != y.sign { sign = 0; @@ -74,7 +74,7 @@ impl FPDecimal { FPDecimal::_mul(*self, FPDecimal::from(other)) } - pub fn _div(x: FPDecimal, y: FPDecimal) -> FPDecimal { + pub(crate) fn _div(x: FPDecimal, y: FPDecimal) -> FPDecimal { if y == FPDecimal::ONE { return x; } diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 60827e9e..94781699 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -1,5 +1,3 @@ -use cosmwasm_std::{OverflowError, OverflowOperation}; -use std::cmp::Ordering; use std::str::FromStr; /// Exponential functions for FPDecimal @@ -7,7 +5,7 @@ use crate::fp_decimal::{FPDecimal, U256}; impl FPDecimal { #[allow(clippy::many_single_char_names)] - pub fn _exp_taylor_expansion(a: FPDecimal, b: FPDecimal) -> FPDecimal { + pub fn exp_taylor_expansion(a: FPDecimal, b: FPDecimal) -> FPDecimal { //a^b n+1 terms taylor expansion let base = a.ln() * b; let mut numerator = base; @@ -105,8 +103,8 @@ impl FPDecimal { if exponent == FPDecimal::TEN.ln() { return Some(FPDecimal::TEN); } - if exponent == FPDecimal::from(11u128).ln() { - return Some(FPDecimal::from(11u128)); + if exponent == FPDecimal::ELEVEN.ln() { + return Some(FPDecimal::ELEVEN); } if exponent == FPDecimal::from(12u128).ln() { return Some(FPDecimal::from(12u128)); @@ -148,8 +146,8 @@ impl FPDecimal { if exponent == (FPDecimal::ONE / FPDecimal::TEN).ln() { return Some(FPDecimal::ONE / FPDecimal::TEN); } - if exponent == (FPDecimal::ONE / FPDecimal::from(11u128)).ln() { - return Some(FPDecimal::ONE / FPDecimal::from(11u128)); + if exponent == (FPDecimal::ONE / FPDecimal::ELEVEN).ln() { + return Some(FPDecimal::ONE / FPDecimal::ELEVEN); } if exponent == (FPDecimal::ONE / FPDecimal::from(12u128)).ln() { return Some(FPDecimal::ONE / FPDecimal::from(12u128)); @@ -196,7 +194,7 @@ impl FPDecimal { if exponent == FPDecimal::TEN { return Some(FPDecimal::from(1024u128)); } - if exponent == FPDecimal::from(11u128) { + if exponent == FPDecimal::ELEVEN { return Some(FPDecimal::from(2048u128)); } if exponent == FPDecimal::from(12u128) { @@ -243,7 +241,7 @@ impl FPDecimal { if exponent == FPDecimal::TEN { return Some(FPDecimal::from(59049u128)); } - if exponent == FPDecimal::from(11u128) { + if exponent == FPDecimal::ELEVEN { return Some(FPDecimal::from(177147u128)); } if exponent == FPDecimal::from(12u128) { @@ -291,7 +289,7 @@ impl FPDecimal { if exponent == FPDecimal::TEN { return Some(FPDecimal::from(9765625u128)); } - if exponent == FPDecimal::from(11u128) { + if exponent == FPDecimal::ELEVEN { return Some(FPDecimal::from(48828125u128)); } if exponent == FPDecimal::from(12u128) { @@ -339,7 +337,7 @@ impl FPDecimal { if exponent == FPDecimal::TEN { return Some(FPDecimal::from(282475249u128)); } - if exponent == FPDecimal::from(11u128) { + if exponent == FPDecimal::ELEVEN { return Some(FPDecimal::from(1977326743u128)); } if exponent == FPDecimal::from(12u128) { @@ -387,7 +385,7 @@ impl FPDecimal { if exponent == FPDecimal::TEN { return Some(FPDecimal::from(10000000000u128)); } - if exponent == FPDecimal::from(11u128) { + if exponent == FPDecimal::ELEVEN { return Some(FPDecimal::from(100000000000u128)); } if exponent == FPDecimal::from(12u128) { @@ -593,9 +591,9 @@ impl FPDecimal { } } - if base == FPDecimal::from(11u128) { + if base == FPDecimal::ELEVEN { if exponent == FPDecimal::ONE { - return Some(FPDecimal::from(11u128)); + return Some(FPDecimal::ELEVEN); } if exponent == FPDecimal::TWO { return Some(FPDecimal::from(121u128)); @@ -624,7 +622,7 @@ impl FPDecimal { if exponent == FPDecimal::TEN { return Some(FPDecimal::from(25937424601u128)); } - if exponent == FPDecimal::from(11u128) { + if exponent == FPDecimal::ELEVEN { return Some(FPDecimal::from(285311670611u128)); } if exponent == FPDecimal::from(12u128) { @@ -659,6 +657,13 @@ impl FPDecimal { panic!("No complex numer"); } } + if exponent.abs() == FPDecimal::ONE / FPDecimal::TWO { + if exponent > FPDecimal::ZERO { + return self.sqrt(); + } else { + return FPDecimal::ONE / self.sqrt(); + } + } fn common_checks(exponent: FPDecimal) -> Option { if FPDecimal::TWO.ln() == exponent { @@ -676,8 +681,8 @@ impl FPDecimal { if FPDecimal::TEN.ln() == exponent { return Some(FPDecimal::TEN); } - if FPDecimal::from(11u128).ln() == exponent { - return Some(FPDecimal::from(11u128)); + if FPDecimal::ELEVEN.ln() == exponent { + return Some(FPDecimal::ELEVEN); } None } @@ -692,13 +697,13 @@ impl FPDecimal { Some(value) => value, None => { let base_checks: Vec = vec![ - (&FPDecimal::_log_e, FPDecimal::E), - (&FPDecimal::_log2, FPDecimal::TWO), - (&FPDecimal::_log3, FPDecimal::THREE), - (&FPDecimal::_log5, FPDecimal::FIVE), - (&FPDecimal::_log7, FPDecimal::SEVEN), - (&FPDecimal::_log10, FPDecimal::TEN), - (&FPDecimal::_log11, FPDecimal::from(11u128)), + (&FPDecimal::log_e, FPDecimal::E), + (&FPDecimal::log2, FPDecimal::TWO), + (&FPDecimal::log3, FPDecimal::THREE), + (&FPDecimal::log5, FPDecimal::FIVE), + (&FPDecimal::log7, FPDecimal::SEVEN), + (&FPDecimal::log10, FPDecimal::TEN), + (&FPDecimal::log11, FPDecimal::ELEVEN), ]; for (log_fn, divisor) in base_checks { if log_fn(exponent).is_some() { @@ -712,6 +717,9 @@ impl FPDecimal { if FPDecimal::ONE / value == exponent { return divisor; } + if FPDecimal::ONE / value == exponent { + return divisor; + } } } FPDecimal::exp(exponent * self.ln()) @@ -759,7 +767,7 @@ impl FPDecimal { val } - pub fn _sqrt(a: FPDecimal) -> Option { + fn _sqrt(a: FPDecimal) -> Option { const MAX_ITERATIONS: i64 = 300; if a < FPDecimal::ZERO { @@ -790,1000 +798,6 @@ impl FPDecimal { None => panic!("Undefined behavior"), } } - - pub fn checked_positive_pow(self, exponent: FPDecimal) -> Result { - { - // This uses the exponentiation by squaring algorithm: - // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method - - if self == FPDecimal::ZERO { - return Ok(FPDecimal::ZERO); - } - if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { - return Ok(FPDecimal::ONE); - } - - if exponent > FPDecimal::from(60u128) { - return Err(OverflowError::new(OverflowOperation::Pow, self.to_string(), exponent.to_string())); - } - - // TODO: need to improve this with exp function - if self == FPDecimal::E { - if exponent == FPDecimal::ONE.ln() { - return Ok(FPDecimal::ONE); - } - if exponent == FPDecimal::TWO.ln() { - return Ok(FPDecimal::TWO); - } - if exponent == FPDecimal::THREE.ln() { - return Ok(FPDecimal::THREE); - } - if exponent == FPDecimal::FOUR.ln() { - return Ok(FPDecimal::FOUR); - } - if exponent == FPDecimal::FIVE.ln() { - return Ok(FPDecimal::FIVE); - } - if exponent == FPDecimal::SIX.ln() { - return Ok(FPDecimal::SIX); - } - if exponent == FPDecimal::SEVEN.ln() { - return Ok(FPDecimal::SEVEN); - } - if exponent == FPDecimal::EIGHT.ln() { - return Ok(FPDecimal::EIGHT); - } - if exponent == FPDecimal::NINE.ln() { - return Ok(FPDecimal::NINE); - } - if exponent == FPDecimal::TEN.ln() { - return Ok(FPDecimal::TEN); - } - if exponent == (FPDecimal::ONE / FPDecimal::TWO).ln() { - return Ok(FPDecimal::ONE / FPDecimal::TWO); - } - if exponent == (FPDecimal::ONE / FPDecimal::THREE).ln() { - return Ok(FPDecimal::ONE / FPDecimal::THREE); - } - if exponent == (FPDecimal::ONE / FPDecimal::FOUR).ln() { - return Ok(FPDecimal::ONE / FPDecimal::FOUR); - } - if exponent == (FPDecimal::ONE / FPDecimal::FIVE).ln() { - return Ok(FPDecimal::ONE / FPDecimal::FIVE); - } - if exponent == (FPDecimal::ONE / FPDecimal::SIX).ln() { - return Ok(FPDecimal::ONE / FPDecimal::SIX); - } - if exponent == (FPDecimal::ONE / FPDecimal::SEVEN).ln() { - return Ok(FPDecimal::ONE / FPDecimal::SEVEN); - } - if exponent == (FPDecimal::ONE / FPDecimal::EIGHT).ln() { - return Ok(FPDecimal::ONE / FPDecimal::EIGHT); - } - if exponent == (FPDecimal::ONE / FPDecimal::NINE).ln() { - return Ok(FPDecimal::ONE / FPDecimal::NINE); - } - if exponent == (FPDecimal::ONE / FPDecimal::TEN).ln() { - return Ok(FPDecimal::ONE / FPDecimal::TEN); - } - } - - if self == FPDecimal::from(10u128) { - if exponent == FPDecimal::ONE { - return Ok(FPDecimal::from(10u128)); - } - if exponent == FPDecimal::TWO { - return Ok(FPDecimal::from(100u128)); - } - if exponent == FPDecimal::THREE { - return Ok(FPDecimal::from(1000u128)); - } - if exponent == FPDecimal::FOUR { - return Ok(FPDecimal::from(10000u128)); - } - if exponent == FPDecimal::FIVE { - return Ok(FPDecimal::from(100000u128)); - } - if exponent == FPDecimal::SIX { - return Ok(FPDecimal::from(1000000u128)); - } - if exponent == FPDecimal::SEVEN { - return Ok(FPDecimal::from(10000000u128)); - } - if exponent == FPDecimal::EIGHT { - return Ok(FPDecimal::from(100000000u128)); - } - if exponent == FPDecimal::NINE { - return Ok(FPDecimal::from(1000000000u128)); - } - if exponent == FPDecimal::TEN { - return Ok(FPDecimal::from(10000000000u128)); - } - if exponent == FPDecimal::from(11u128) { - return Ok(FPDecimal::from(100000000000u128)); - } - if exponent == FPDecimal::from(12u128) { - return Ok(FPDecimal::from(1000000000000u128)); - } - if exponent == FPDecimal::from(13u128) { - return Ok(FPDecimal::from(10000000000000u128)); - } - if exponent == FPDecimal::from(14u128) { - return Ok(FPDecimal::from(100000000000000u128)); - } - if exponent == FPDecimal::from(15u128) { - return Ok(FPDecimal::from(1000000000000000u128)); - } - if exponent == FPDecimal::from(16u128) { - return Ok(FPDecimal::from(10000000000000000u128)); - } - if exponent == FPDecimal::from(17u128) { - return Ok(FPDecimal::from(100000000000000000u128)); - } - if exponent == FPDecimal::from(18u128) { - return Ok(FPDecimal::from(1000000000000000000u128)); - } - if exponent == FPDecimal::from(19u128) { - return Ok(FPDecimal::from(10000000000000000000u128)); - } - if exponent == FPDecimal::from(20u128) { - return Ok(FPDecimal::from(100000000000000000000u128)); - } - if exponent == FPDecimal::NEGATIVE_ONE { - return Ok(FPDecimal::from_str("0.1").unwrap()); - } - if exponent == FPDecimal::from_str("-2").unwrap() { - return Ok(FPDecimal::from_str("0.01").unwrap()); - } - if exponent == FPDecimal::from_str("-3").unwrap() { - return Ok(FPDecimal::from_str("0.001").unwrap()); - } - if exponent == FPDecimal::from_str("-4").unwrap() { - return Ok(FPDecimal::from_str("0.0001").unwrap()); - } - if exponent == FPDecimal::from_str("-5").unwrap() { - return Ok(FPDecimal::from_str("0.00001").unwrap()); - } - if exponent == FPDecimal::from_str("-6").unwrap() { - return Ok(FPDecimal::from_str("0.000001").unwrap()); - } - if exponent == FPDecimal::from_str("-7").unwrap() { - return Ok(FPDecimal::from_str("0.0000001").unwrap()); - } - if exponent == FPDecimal::from_str("-8").unwrap() { - return Ok(FPDecimal::from_str("0.00000001").unwrap()); - } - if exponent == FPDecimal::from_str("-9").unwrap() { - return Ok(FPDecimal::from_str("0.000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-10").unwrap() { - return Ok(FPDecimal::from_str("0.0000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-11").unwrap() { - return Ok(FPDecimal::from_str("0.00000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-12").unwrap() { - return Ok(FPDecimal::from_str("0.000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-13").unwrap() { - return Ok(FPDecimal::from_str("0.0000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-14").unwrap() { - return Ok(FPDecimal::from_str("0.00000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-15").unwrap() { - return Ok(FPDecimal::from_str("0.000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-16").unwrap() { - return Ok(FPDecimal::from_str("0.0000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-17").unwrap() { - return Ok(FPDecimal::from_str("0.00000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-18").unwrap() { - return Ok(FPDecimal::from_str("0.000000000000000001").unwrap()); - } - if exponent < FPDecimal::from_str("-18").unwrap() { - return Ok(FPDecimal::ZERO); - } - if exponent == FPDecimal::from(21u128) { - return Ok(FPDecimal::from(1000000000000000000000u128)); - } - if exponent == FPDecimal::from(22u128) { - return Ok(FPDecimal::from(10000000000000000000000u128)); - } - if exponent == FPDecimal::from(23u128) { - return Ok(FPDecimal::from(100000000000000000000000u128)); - } - if exponent == FPDecimal::from(24u128) { - return Ok(FPDecimal::from(1000000000000000000000000u128)); - } - if exponent == FPDecimal::from(25u128) { - return Ok(FPDecimal::from(10000000000000000000000000u128)); - } - if exponent == FPDecimal::from(26u128) { - return Ok(FPDecimal::from(100000000000000000000000000u128)); - } - if exponent == FPDecimal::from(27u128) { - return Ok(FPDecimal::from(1000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(28u128) { - return Ok(FPDecimal::from(10000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(29u128) { - return Ok(FPDecimal::from(100000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(30u128) { - return Ok(FPDecimal::from(1000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(31u128) { - return Ok(FPDecimal::from(10000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(32u128) { - return Ok(FPDecimal::from(100000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(33u128) { - return Ok(FPDecimal::from(1000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(34u128) { - return Ok(FPDecimal::from(10000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(35u128) { - return Ok(FPDecimal::from(100000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(36u128) { - return Ok(FPDecimal::from(1000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(37u128) { - return Ok(FPDecimal::from(10000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(38u128) { - return Ok(FPDecimal::from(100000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(39u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(40u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(41u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(42u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(43u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(44u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(45u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(46u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(47u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(48u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(49u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(50u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(51u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(52u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(53u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(54u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(55u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(56u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(57u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(58u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(59u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000000").unwrap()); - } - } - - fn compute_exponentiation(base: FPDecimal, mut exponent: FPDecimal) -> Result { - // base^exponent - // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers - // 14 terms taylor expansion provides a good enough approximation - //const N_TERMS: u128 = 13; - match exponent.cmp(&FPDecimal::ZERO) { - Ordering::Equal => Ok(FPDecimal::ONE), - // Negative exponent - Ordering::Less => { - exponent = -exponent; - match exponent.cmp(&(FPDecimal::ONE)) { - Ordering::Equal => Ok(FPDecimal::ONE / base), - Ordering::Less => compute_negative_exponent_less_one(base, exponent), - Ordering::Greater => compute_negative_exponent_greater_one(base, exponent), - } - } - // Positive exponent - Ordering::Greater => match exponent.cmp(&FPDecimal::ONE) { - Ordering::Equal => Ok(base), - Ordering::Less => compute_positive_exponent_less_one(base, exponent), - Ordering::Greater => compute_positive_exponent_greater_one(base, exponent), - }, - } - } - - fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { - let mut int_b = exponent.int(); - let rem_b = exponent - int_b; - let mut float_exp = FPDecimal::ONE; - if rem_b != FPDecimal::ZERO { - float_exp = FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, rem_b); - } - let mut tmp_a = FPDecimal::ONE; - while int_b > FPDecimal::ONE { - if int_b.num % FPDecimal::TWO.num == FPDecimal::ONE.num { - tmp_a = base * tmp_a; - int_b -= FPDecimal::ONE; - } - base = base * base; - int_b /= FPDecimal::TWO; - } - base *= tmp_a; - Ok(FPDecimal::ONE / base * float_exp) - } - - fn negative_exponent_check_basic_log( - mut base: FPDecimal, - exponent: FPDecimal, - reciprocal: FPDecimal, - log_base: FPDecimal, - ) -> Option { - let mut temp_exponent_reciprocal = FPDecimal::reciprocal(exponent).int(); - - let abs_difference: FPDecimal = FPDecimal::must_from_str("0.0000001"); - // reciprocal is odd - if ((FPDecimal::reciprocal(exponent) % FPDecimal::TWO).int() - FPDecimal::ONE).abs() <= abs_difference { - while temp_exponent_reciprocal > FPDecimal::ONE { - base /= log_base; - temp_exponent_reciprocal -= FPDecimal::ONE; - } - return Some(FPDecimal::ONE / base); - } - // reciprocal is even - if reciprocal % FPDecimal::TWO == FPDecimal::ZERO { - while temp_exponent_reciprocal > FPDecimal::ONE { - base = base.sqrt(); - temp_exponent_reciprocal /= FPDecimal::TWO; - } - return Some(FPDecimal::ONE / base); - } - None - } - - type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); - - fn compute_negative_exponent_less_one(base: FPDecimal, exponent: FPDecimal) -> Result { - // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers - let abs_error = FPDecimal::must_from_str("0.00000000000000001"); - let reciprocal = if (FPDecimal::reciprocal(exponent) - FPDecimal::reciprocal(exponent).int()).abs() < abs_error { - FPDecimal::reciprocal(exponent).int() - } else { - FPDecimal::reciprocal(exponent) - }; - - let base_checks: Vec = vec![ - (&FPDecimal::_log_e, FPDecimal::E), - (&FPDecimal::_log2, FPDecimal::TWO), - (&FPDecimal::_log3, FPDecimal::THREE), - (&FPDecimal::_log5, FPDecimal::FIVE), - (&FPDecimal::_log7, FPDecimal::SEVEN), - (&FPDecimal::_log10, FPDecimal::TEN), - (&FPDecimal::_log11, FPDecimal::from(11u128)), - ]; - - for (log_fn, divisor) in base_checks { - if log_fn(base).is_some() { - if log_fn(base).unwrap().abs() >= reciprocal { - if let Some(value) = negative_exponent_check_basic_log(base, exponent, reciprocal, divisor) { - return Ok(value); - } - } else { - let multiplier = log_fn(base).unwrap(); - return Ok(multiplier * divisor.ln() / reciprocal); - } - } - } - - Ok(FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, exponent)) - } - - fn positive_exponent_check_basic_log( - mut base: FPDecimal, - exponent: FPDecimal, - reciprocal: FPDecimal, - log_base: FPDecimal, - ) -> Option { - let mut temp_b = FPDecimal::reciprocal(exponent).int(); - let abs_difference: FPDecimal = FPDecimal::must_from_str("0.0000001"); - - // odd - if ((reciprocal % FPDecimal::TWO).int() - FPDecimal::ONE).abs() <= abs_difference { - while temp_b > FPDecimal::ONE { - base /= log_base; - temp_b -= FPDecimal::ONE; - } - return Some(base); - }; - - // even - if reciprocal % FPDecimal::TWO == FPDecimal::ZERO { - while temp_b > FPDecimal::ONE { - base = base.sqrt(); - temp_b /= FPDecimal::TWO; - } - return Some(base); - }; - None - } - - fn compute_positive_exponent_less_one(base: FPDecimal, exponent: FPDecimal) -> Result { - // taylor expansion approximation of exponentiation computation with float number exponent - // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers - let abs_error = FPDecimal::must_from_str("0.00000000000000001"); - let reciprocal = if (FPDecimal::reciprocal(exponent) - FPDecimal::reciprocal(exponent).int()).abs() < abs_error { - FPDecimal::reciprocal(exponent).int() - } else { - FPDecimal::reciprocal(exponent) - }; - let base_checks: Vec = vec![ - (&FPDecimal::_log_e, FPDecimal::E), - (&FPDecimal::_log2, FPDecimal::TWO), - (&FPDecimal::_log3, FPDecimal::THREE), - (&FPDecimal::_log5, FPDecimal::FIVE), - (&FPDecimal::_log7, FPDecimal::SEVEN), - (&FPDecimal::_log10, FPDecimal::TEN), - (&FPDecimal::_log11, FPDecimal::from(11u128)), - ]; - - for (log_fn, divisor) in base_checks { - if log_fn(base).is_some() && log_fn(base).unwrap().abs() >= reciprocal { - if let Some(value) = positive_exponent_check_basic_log(base, exponent, reciprocal, divisor) { - return Ok(value); - } - } - } - - Ok(FPDecimal::_exp_taylor_expansion(base, exponent)) - } - - fn compute_integer_exponentiation(mut base: FPDecimal, mut exponent: FPDecimal) -> FPDecimal { - let mut temp_base = FPDecimal::ONE; - - while exponent > FPDecimal::ONE { - if exponent.num % FPDecimal::TWO.num == FPDecimal::ONE.num { - temp_base = base * temp_base; - exponent -= FPDecimal::ONE; - } - - base = base * base; - exponent /= FPDecimal::TWO; - } - - base * temp_base - } - - fn compute_positive_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { - let integer_part_of_exponent = exponent.int(); - let fractional_part_of_exponent = exponent - integer_part_of_exponent; - - let fractional_exponentiation = if fractional_part_of_exponent != FPDecimal::ZERO { - FPDecimal::_exp_taylor_expansion(base, fractional_part_of_exponent) - } else { - FPDecimal::ONE - }; - - base = compute_integer_exponentiation(base, integer_part_of_exponent); - - Ok(base * fractional_exponentiation) - } - - compute_exponentiation(self, exponent).map_err(|_| OverflowError { - operation: OverflowOperation::Pow, - operand1: self.to_string(), - operand2: exponent.to_string(), - }) - } - } - - pub fn checked_negative_pow(self, exponent: FPDecimal) -> Result { - { - // This uses the exponentiation by squaring algorithm: - // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method - - if self == FPDecimal::ZERO { - return Ok(FPDecimal::ZERO); - } - if self.is_negative() && exponent == FPDecimal::ZERO { - return Ok(FPDecimal::NEGATIVE_ONE); - } - if exponent > FPDecimal::from(60u128) { - return Err(OverflowError::new(OverflowOperation::Pow, self.to_string(), exponent.to_string())); - } - if self == -FPDecimal::E { - let e = FPDecimal::E; - if exponent == FPDecimal::ONE { - return Ok(-e); - } - if exponent == FPDecimal::TWO { - return Ok(e * e); - } - if exponent == FPDecimal::THREE { - return Ok(-e * e * e); - } - if exponent == FPDecimal::FOUR { - return Ok(e * e * e * e); - } - if exponent == FPDecimal::FIVE { - return Ok(-e * e * e * e * e); - } - if exponent == FPDecimal::SIX { - return Ok(e * e * e * e * e * e); - } - if exponent == FPDecimal::SEVEN { - return Ok(-e * e * e * e * e * e * e); - } - if exponent == FPDecimal::EIGHT { - return Ok(e * e * e * e * e * e * e * e); - } - if exponent == FPDecimal::NINE { - return Ok(-e * e * e * e * e * e * e * e * e); - } - if exponent == FPDecimal::TEN { - return Ok(e * e * e * e * e * e * e * e * e * e); - } - if exponent == -FPDecimal::TWO { - return Ok((FPDecimal::ONE) / (e * e)); - } - if exponent == -FPDecimal::THREE { - return Ok(-(FPDecimal::ONE) / (e * e * e)); - } - if exponent == -FPDecimal::FOUR { - return Ok((FPDecimal::ONE) / (e * e * e * e)); - } - if exponent == -FPDecimal::FIVE { - return Ok(-(FPDecimal::ONE) / (e * e * e * e * e)); - } - if exponent == -FPDecimal::SIX { - return Ok((FPDecimal::ONE) / (e * e * e * e * e * e)); - } - if exponent == -FPDecimal::SEVEN { - return Ok(-(FPDecimal::ONE) / (e * e * e * e * e * e * e)); - } - if exponent == -FPDecimal::EIGHT { - return Ok((FPDecimal::ONE) / (e * e * e * e * e * e * e * e)); - } - if exponent == -FPDecimal::NINE { - return Ok(-(FPDecimal::ONE) / (e * e * e * e * e * e * e * e * e)); - } - if exponent == -FPDecimal::TEN { - return Ok((FPDecimal::ONE) / (e * e * e * e * e * e * e * e * e * e)); - } - } - - if self == -FPDecimal::from(10u128) { - if exponent == FPDecimal::ONE { - return Ok(-FPDecimal::from(10u128)); - } - if exponent == FPDecimal::TWO { - return Ok(FPDecimal::from(100u128)); - } - if exponent == FPDecimal::THREE { - return Ok(-FPDecimal::from(1000u128)); - } - if exponent == FPDecimal::FOUR { - return Ok(-FPDecimal::from(10000u128)); - } - if exponent == FPDecimal::FIVE { - return Ok(-FPDecimal::from(100000u128)); - } - if exponent == FPDecimal::SIX { - return Ok(FPDecimal::from(1000000u128)); - } - if exponent == FPDecimal::SEVEN { - return Ok(-FPDecimal::from(10000000u128)); - } - if exponent == FPDecimal::EIGHT { - return Ok(FPDecimal::from(100000000u128)); - } - if exponent == FPDecimal::NINE { - return Ok(-FPDecimal::from(1000000000u128)); - } - if exponent == FPDecimal::from(10u128) { - return Ok(FPDecimal::from(10000000000u128)); - } - if exponent == FPDecimal::from(11u128) { - return Ok(-FPDecimal::from(100000000000u128)); - } - if exponent == FPDecimal::from(12u128) { - return Ok(FPDecimal::from(1000000000000u128)); - } - if exponent == FPDecimal::from(13u128) { - return Ok(-FPDecimal::from(10000000000000u128)); - } - if exponent == FPDecimal::from(14u128) { - return Ok(FPDecimal::from(100000000000000u128)); - } - if exponent == FPDecimal::from(15u128) { - return Ok(-FPDecimal::from(1000000000000000u128)); - } - if exponent == FPDecimal::from(16u128) { - return Ok(FPDecimal::from(10000000000000000u128)); - } - if exponent == FPDecimal::from(17u128) { - return Ok(-FPDecimal::from(100000000000000000u128)); - } - if exponent == FPDecimal::from(18u128) { - return Ok(FPDecimal::from(1000000000000000000u128)); - } - if exponent == FPDecimal::from(19u128) { - return Ok(-FPDecimal::from(10000000000000000000u128)); - } - if exponent == FPDecimal::from(20u128) { - return Ok(FPDecimal::from(100000000000000000000u128)); - } - if exponent == FPDecimal::NEGATIVE_ONE { - return Ok(-FPDecimal::from_str("0.1").unwrap()); - } - if exponent == FPDecimal::from_str("-2").unwrap() { - return Ok(FPDecimal::from_str("0.01").unwrap()); - } - if exponent == FPDecimal::from_str("-3").unwrap() { - return Ok(-FPDecimal::from_str("0.001").unwrap()); - } - if exponent == FPDecimal::from_str("-4").unwrap() { - return Ok(FPDecimal::from_str("0.0001").unwrap()); - } - if exponent == FPDecimal::from_str("-5").unwrap() { - return Ok(-FPDecimal::from_str("0.00001").unwrap()); - } - if exponent == FPDecimal::from_str("-6").unwrap() { - return Ok(FPDecimal::from_str("0.000001").unwrap()); - } - if exponent == FPDecimal::from_str("-7").unwrap() { - return Ok(-FPDecimal::from_str("0.0000001").unwrap()); - } - if exponent == FPDecimal::from_str("-8").unwrap() { - return Ok(FPDecimal::from_str("0.00000001").unwrap()); - } - if exponent == FPDecimal::from_str("-9").unwrap() { - return Ok(-FPDecimal::from_str("0.000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-10").unwrap() { - return Ok(FPDecimal::from_str("0.0000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-11").unwrap() { - return Ok(-FPDecimal::from_str("0.00000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-12").unwrap() { - return Ok(FPDecimal::from_str("0.000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-13").unwrap() { - return Ok(-FPDecimal::from_str("0.0000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-14").unwrap() { - return Ok(FPDecimal::from_str("0.00000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-15").unwrap() { - return Ok(-FPDecimal::from_str("0.000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-16").unwrap() { - return Ok(FPDecimal::from_str("0.0000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-17").unwrap() { - return Ok(-FPDecimal::from_str("0.00000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-18").unwrap() { - return Ok(FPDecimal::from_str("0.000000000000000001").unwrap()); - } - if exponent < FPDecimal::from_str("-18").unwrap() { - return Ok(FPDecimal::ZERO); - } - - if exponent == FPDecimal::from(21u128) { - return Ok(-FPDecimal::from(1000000000000000000000u128)); - } - if exponent == FPDecimal::from(22u128) { - return Ok(-FPDecimal::from(10000000000000000000000u128)); - } - if exponent == FPDecimal::from(23u128) { - return Ok(-FPDecimal::from(100000000000000000000000u128)); - } - if exponent == FPDecimal::from(24u128) { - return Ok(FPDecimal::from(1000000000000000000000000u128)); - } - if exponent == FPDecimal::from(25u128) { - return Ok(-FPDecimal::from(10000000000000000000000000u128)); - } - if exponent == FPDecimal::from(26u128) { - return Ok(FPDecimal::from(100000000000000000000000000u128)); - } - if exponent == FPDecimal::from(27u128) { - return Ok(-FPDecimal::from(1000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(28u128) { - return Ok(FPDecimal::from(10000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(29u128) { - return Ok(-FPDecimal::from(100000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(30u128) { - return Ok(FPDecimal::from(1000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(31u128) { - return Ok(-FPDecimal::from(10000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(32u128) { - return Ok(FPDecimal::from(100000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(33u128) { - return Ok(-FPDecimal::from(1000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(34u128) { - return Ok(FPDecimal::from(10000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(35u128) { - return Ok(-FPDecimal::from(100000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(36u128) { - return Ok(FPDecimal::from(1000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(37u128) { - return Ok(-FPDecimal::from(10000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(38u128) { - return Ok(FPDecimal::from(100000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(39u128) { - return Ok(-FPDecimal::from_str("1000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(40u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(41u128) { - return Ok(-FPDecimal::from_str("100000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(42u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(43u128) { - return Ok(-FPDecimal::from_str("10000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(44u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(45u128) { - return Ok(-FPDecimal::from_str("1000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(46u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(47u128) { - return Ok(-FPDecimal::from_str("100000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(48u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(49u128) { - return Ok(-FPDecimal::from_str("10000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(50u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(51u128) { - return Ok(-FPDecimal::from_str("1000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(52u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(53u128) { - return Ok(-FPDecimal::from_str("100000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(54u128) { - return Ok(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(55u128) { - return Ok(-FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(56u128) { - return Ok(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(57u128) { - return Ok(-FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(58u128) { - return Ok(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(59u128) { - return Ok(-FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000000").unwrap()); - } - } - - fn compute_exponentiation(base: FPDecimal, mut exponent: FPDecimal) -> Result { - // a^b - // 14 terms taylor expansion provides a good enough approximation - match exponent.cmp(&FPDecimal::ZERO) { - Ordering::Equal => Ok(FPDecimal::ONE), - Ordering::Less => { - exponent = -exponent; - match exponent.cmp(&(FPDecimal::ONE)) { - Ordering::Equal => Ok(FPDecimal::ONE / base), - Ordering::Less => compute_negative_exponent_less_one(FPDecimal::ONE / base, exponent), - Ordering::Greater => compute_negative_exponent_greater_one(FPDecimal::ONE / base, exponent), - } - } - Ordering::Greater => match exponent.cmp(&FPDecimal::ONE) { - Ordering::Equal => Ok(base), - Ordering::Less => compute_positive_exponent_less_one(base, exponent), - Ordering::Greater => compute_positive_exponent_greater_one(base, exponent), - }, - } - } - - type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); - - fn compute_negative_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { - // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers - base = -base; - - let base_checks: Vec = vec![ - (&FPDecimal::_log2, FPDecimal::TWO), - (&FPDecimal::_log_e, FPDecimal::E), - (&FPDecimal::_log3, FPDecimal::THREE), - (&FPDecimal::_log5, FPDecimal::FIVE), - (&FPDecimal::_log7, FPDecimal::SEVEN), - (&FPDecimal::_log10, FPDecimal::TEN), - ]; - - for (log_fn, divisor) in base_checks { - if log_fn(base).is_some() && check_conditions_and_return_negative(base, divisor, &exponent) { - return Ok(-base); - } - } - - // Handling log11 case separately - if (base)._log11().is_some() && check_conditions_and_return_negative(base, FPDecimal::from(11u128), &exponent) { - return Ok(-FPDecimal::ONE / base); - } - - Ok(FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, exponent)) - } - - fn check_conditions_and_return_negative(mut base: FPDecimal, divisor: FPDecimal, exponent: &FPDecimal) -> bool { - let abs_error = FPDecimal::must_from_str("0.00000000000000001"); - let reciprocal = if (FPDecimal::reciprocal(*exponent) - FPDecimal::reciprocal(*exponent).int()).abs() < abs_error { - FPDecimal::reciprocal(*exponent).int() - } else { - FPDecimal::reciprocal(*exponent) - }; - - if reciprocal % FPDecimal::TWO == FPDecimal::ZERO { - panic!("No complex number"); - }; - - if ((FPDecimal::reciprocal(*exponent) % FPDecimal::TWO).int() - FPDecimal::ONE).abs() <= FPDecimal::must_from_str("0.000001") { - let mut tmp_b = FPDecimal::reciprocal(*exponent).int(); - while tmp_b > FPDecimal::ONE { - base /= divisor; - tmp_b -= FPDecimal::ONE; - } - true - } else { - false - } - } - - fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { - let integer_part_of_exponent = exponent.int(); - let fractional_part_of_exponent = exponent - integer_part_of_exponent; - - let fractional_exponentiation = if fractional_part_of_exponent != FPDecimal::ZERO { - FPDecimal::_exp_taylor_expansion(FPDecimal::ONE / base, fractional_part_of_exponent) - } else { - FPDecimal::ONE - }; - base = compute_integer_exponentiation(base, integer_part_of_exponent); - Ok(FPDecimal::ONE / base * fractional_exponentiation) - } - - fn compute_positive_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal) -> Result { - // taylor expansion approximation of exponentiation computation with float number exponent - // NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers - base = -base; - - // Define a list of base-check functions and their corresponding values - let base_checks: Vec = vec![ - (&FPDecimal::_log2, FPDecimal::TWO), - (&FPDecimal::_log_e, FPDecimal::E), - (&FPDecimal::_log3, FPDecimal::THREE), - (&FPDecimal::_log5, FPDecimal::FIVE), - (&FPDecimal::_log7, FPDecimal::SEVEN), - (&FPDecimal::_log10, FPDecimal::TEN), - (&FPDecimal::_log11, FPDecimal::from(11u128)), - ]; - - for (log_fn, divisor) in &base_checks { - if log_fn(base).is_some() && check_conditions_and_return(&mut base, divisor, &exponent) { - return Ok(-base); - } - } - - Ok(FPDecimal::_exp_taylor_expansion(base, exponent)) - } - - fn check_conditions_and_return(base: &mut FPDecimal, divisor: &FPDecimal, exponent: &FPDecimal) -> bool { - if FPDecimal::reciprocal(*exponent) % FPDecimal::TWO == FPDecimal::ZERO { - panic!("No complex number"); - }; - - if ((FPDecimal::reciprocal(*exponent) % FPDecimal::TWO).int() - FPDecimal::ONE).abs() <= FPDecimal::must_from_str("0.000001") { - let mut tmp_b = FPDecimal::reciprocal(*exponent).int(); - while tmp_b > FPDecimal::ONE { - *base /= *divisor; - tmp_b -= FPDecimal::ONE; - } - true - } else { - false - } - } - - fn compute_integer_exponentiation(mut base: FPDecimal, mut exponent: FPDecimal) -> FPDecimal { - let mut temp_base = FPDecimal::ONE; - while exponent > FPDecimal::ONE { - if exponent.num % FPDecimal::TWO.num == FPDecimal::ONE.num { - temp_base = base * temp_base; - exponent -= FPDecimal::ONE; - } - base = base * base; - exponent /= FPDecimal::TWO; - } - base * temp_base - } - - fn compute_positive_exponent_greater_one(base: FPDecimal, exponent: FPDecimal) -> Result { - let integer_part_of_exponent = exponent.int(); - let fractional_part_of_exponent = exponent - integer_part_of_exponent; - if fractional_part_of_exponent != FPDecimal::ZERO { - panic!("No complex number"); - } - Ok(compute_integer_exponentiation(base, integer_part_of_exponent)) - } - - compute_exponentiation(self, exponent).map_err(|_| OverflowError { - operation: OverflowOperation::Pow, - operand1: self.to_string(), - operand2: exponent.to_string(), - }) - } - } } #[cfg(test)] @@ -1798,7 +812,7 @@ mod tests { // a^x = e^(xln(a)) // 3^2.3 = e(2.3ln(3)) assert_eq!( - FPDecimal::_exp_taylor_expansion(FPDecimal::THREE, FPDecimal::must_from_str("2.3")), + FPDecimal::exp_taylor_expansion(FPDecimal::THREE, FPDecimal::must_from_str("2.3")), // 12.513502532843181622 FPDecimal::must_from_str("12.513502532843184097") ); @@ -2059,7 +1073,7 @@ mod tests { fn test_121_pow_0_5() { assert_eq!( FPDecimal::pow(FPDecimal::from(121u128), FPDecimal::must_from_str("0.5")), - FPDecimal::from(11u128) + FPDecimal::ELEVEN ); } @@ -2074,7 +1088,7 @@ mod tests { fn test_1331_pow_1_over_3() { assert_eq!( FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::ONE / FPDecimal::THREE), - FPDecimal::from(11u128) + FPDecimal::ELEVEN ); } @@ -2082,7 +1096,7 @@ mod tests { fn test_14641_pow_0_25() { assert_eq!( FPDecimal::pow(FPDecimal::from(14641u128), FPDecimal::ONE / FPDecimal::FOUR), - FPDecimal::from(11u128) + FPDecimal::ELEVEN ); } @@ -2215,7 +1229,7 @@ mod tests { fn test_checked_2_pow_2() { let base = FPDecimal::from(2u128); - let result = FPDecimal::checked_positive_pow(base, FPDecimal::from(2u128)).unwrap(); + let result = FPDecimal::pow(base, FPDecimal::from(2u128)); assert_eq!(result, FPDecimal::from(4u128)); } @@ -2281,7 +1295,7 @@ mod tests { let base = FPDecimal::ONE / FPDecimal::from(16u128); let exponent = FPDecimal::must_from_str("-0.5"); - let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + let result = FPDecimal::pow(base, exponent); assert_eq!(result, FPDecimal::FOUR); } @@ -2290,7 +1304,8 @@ mod tests { let base = FPDecimal::ONE / FPDecimal::from(16u128); let exponent = FPDecimal::must_from_str("0.5"); - let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + // let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); + let result = FPDecimal::pow(base, exponent); assert_eq!(result, FPDecimal::ONE / FPDecimal::FOUR); } diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs index ecf5a223..f0a6d8fe 100644 --- a/packages/injective-math/src/fp_decimal/from_str.rs +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -39,7 +39,6 @@ impl FromStr for FPDecimal { } _ => Err(StdError::generic_err("Unexpected number of dots")), } - //Ok(FPDecimal {num: num * FPDecimal::ONE.num, sign: sign}) } } diff --git a/packages/injective-math/src/fp_decimal/hyper.rs b/packages/injective-math/src/fp_decimal/hyper.rs index 3eb65a81..d38fa341 100644 --- a/packages/injective-math/src/fp_decimal/hyper.rs +++ b/packages/injective-math/src/fp_decimal/hyper.rs @@ -2,7 +2,7 @@ use crate::fp_decimal::{FPDecimal, U256}; impl FPDecimal { - pub fn _sinh(x: FPDecimal) -> FPDecimal { + pub(crate) fn _sinh(x: FPDecimal) -> FPDecimal { let neg_x: FPDecimal = FPDecimal { num: x.num, sign: 1 - x.sign, @@ -19,7 +19,7 @@ impl FPDecimal { FPDecimal::_sinh(*self) } - pub fn _cosh(x: FPDecimal) -> FPDecimal { + pub(crate) fn _cosh(x: FPDecimal) -> FPDecimal { let neg_x: FPDecimal = FPDecimal { num: x.num, sign: 1 - x.sign, @@ -36,7 +36,7 @@ impl FPDecimal { FPDecimal::_cosh(*self) } - pub fn _tanh(x: FPDecimal) -> FPDecimal { + pub(crate) fn _tanh(x: FPDecimal) -> FPDecimal { FPDecimal::_div(FPDecimal::_sinh(x), FPDecimal::_cosh(x)) } diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 529c4bee..0961f78c 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -2,34 +2,34 @@ use crate::fp_decimal::{FPDecimal, U256}; impl FPDecimal { - pub fn _log_const(self) -> Option<(FPDecimal, u128)> { - if let Some(value) = self._log2() { + fn _log_const(self) -> Option<(FPDecimal, u128)> { + if let Some(value) = self.log2() { return Some((value, 2u128)); } - if let Some(value) = self._log_e() { + if let Some(value) = self.log_e() { //NOTE: base e can't be represented by u128, so we use 27 in here return Some((value, 27u128)); } - if let Some(value) = self._log3() { + if let Some(value) = self.log3() { return Some((value, 3u128)); } - if let Some(value) = self._log5() { + if let Some(value) = self.log5() { return Some((value, 5u128)); } - if let Some(value) = self._log7() { + if let Some(value) = self.log7() { return Some((value, 7u128)); } - if let Some(value) = self._log10() { + if let Some(value) = self.log10() { return Some((value, 10u128)); } - if let Some(value) = self._log11() { + if let Some(value) = self.log11() { return Some((value, 11u128)); } None } - pub fn _log_e(self) -> Option { + pub(crate) fn log_e(self) -> Option { let e = FPDecimal::E; if self == FPDecimal::ONE { return Some(FPDecimal::ZERO); @@ -97,7 +97,7 @@ impl FPDecimal { None } - pub fn _log2(self) -> Option { + pub(crate) fn log2(self) -> Option { if self == FPDecimal::ONE { return Some(FPDecimal::ZERO); } @@ -164,7 +164,7 @@ impl FPDecimal { None } - pub fn _log3(self) -> Option { + pub(crate) fn log3(self) -> Option { if self == FPDecimal::ONE { return Some(FPDecimal::ZERO); } @@ -232,7 +232,7 @@ impl FPDecimal { None } - pub fn _log5(self) -> Option { + pub(crate) fn log5(self) -> Option { if self == FPDecimal::ONE { return Some(FPDecimal::ZERO); } @@ -300,7 +300,7 @@ impl FPDecimal { } // 7^1..10 - pub fn _log7(self) -> Option { + pub(crate) fn log7(self) -> Option { if self == FPDecimal::ONE { return Some(FPDecimal::ZERO); } @@ -367,7 +367,7 @@ impl FPDecimal { None } - pub fn _log10(self) -> Option { + pub(crate) fn log10(self) -> Option { if self == FPDecimal::ONE { return Some(FPDecimal::ZERO); } @@ -436,11 +436,11 @@ impl FPDecimal { } // 11^1..10 - pub fn _log11(self) -> Option { + pub(crate) fn log11(self) -> Option { if self == FPDecimal::ONE { return Some(FPDecimal::ZERO); } - if self == FPDecimal::from(11u128) { + if self == FPDecimal::ELEVEN { return Some(FPDecimal::ONE); } if self == FPDecimal::from(121u128) { @@ -470,7 +470,7 @@ impl FPDecimal { if self == FPDecimal::from(25937424601u128) { return Some(FPDecimal::TEN); } - if self == FPDecimal::ONE / FPDecimal::from(11u128) { + if self == FPDecimal::ONE / FPDecimal::ELEVEN { return Some(-FPDecimal::ONE); } if self == FPDecimal::ONE / FPDecimal::from(121u128) { @@ -503,7 +503,7 @@ impl FPDecimal { None } - pub fn _log(a: FPDecimal, base: FPDecimal) -> FPDecimal { + fn _log(a: FPDecimal, base: FPDecimal) -> FPDecimal { // NOTE: only accurate 1,3,5,7,11, and combinations of these 4 numbers //log_base^b = ln(a)/ln(base) if a == FPDecimal::ONE { @@ -517,19 +517,6 @@ impl FPDecimal { a.ln() / base.ln() } - /// natural logarithm - - #[allow(clippy::many_single_char_names)] - pub fn _ln_greater_than_one(mut a: FPDecimal) -> FPDecimal { - // ln(123.456) => ln(1.23456 * 10^2) =>ln(1.23456)+2ln(10) - let mut exponent = 0u128; - while a > FPDecimal::ONE { - a /= FPDecimal::TEN; - exponent += 1; - } - a.ln() + FPDecimal::from(exponent) * FPDecimal::TEN.ln() - } - #[allow(clippy::many_single_char_names)] fn _two_agm(mut a0: FPDecimal, mut b0: FPDecimal, tol: FPDecimal) -> FPDecimal { loop { @@ -634,7 +621,7 @@ impl FPDecimal { if *self == FPDecimal::TWO { return FPDecimal::LN2; } - if let Some(value) = self._log_e() { + if let Some(value) = self.log_e() { return value; } if self.abs() < FPDecimal::must_from_str("1.1") { @@ -691,7 +678,7 @@ mod tests { assert_eq!((FPDecimal::ONE / FPDecimal::TEN).ln(), FPDecimal::must_from_str("-2.302585092978637669")); assert_eq!( - (FPDecimal::ONE / FPDecimal::from(11u128)).ln(), + (FPDecimal::ONE / FPDecimal::ELEVEN).ln(), FPDecimal::must_from_str("-2.397895272724232098") ); assert_eq!( @@ -750,10 +737,7 @@ mod tests { #[test] fn test_log_11_8() { - assert_eq!( - FPDecimal::EIGHT.log(FPDecimal::from(11u128)), - FPDecimal::must_from_str("0.867194478953663578") - ); + assert_eq!(FPDecimal::EIGHT.log(FPDecimal::ELEVEN), FPDecimal::must_from_str("0.867194478953663578")); } #[test] @@ -781,8 +765,6 @@ mod tests { sign: 1, }; let two_point_three = two + three / FPDecimal::from(10u128); - //0.832909124129605490, - // 0.8329091229351039296 assert_eq!(two_point_three.ln(), FPDecimal::must_from_str("0.832909122935103999")); } diff --git a/packages/injective-math/src/fp_decimal/mod.rs b/packages/injective-math/src/fp_decimal/mod.rs index 23cd447a..750f8e90 100644 --- a/packages/injective-math/src/fp_decimal/mod.rs +++ b/packages/injective-math/src/fp_decimal/mod.rs @@ -186,6 +186,11 @@ impl FPDecimal { sign: 1, }; + pub const ELEVEN: FPDecimal = FPDecimal { + num: U256([11_000_000_000_000_000_000, 0, 0, 0]), + sign: 1, + }; + pub const SMALLEST_PRECISION: FPDecimal = FPDecimal { num: U256([1, 0, 0, 0]), sign: 1, diff --git a/packages/injective-math/src/fp_decimal/trigonometry.rs b/packages/injective-math/src/fp_decimal/trigonometry.rs index 32f53134..6035b5da 100644 --- a/packages/injective-math/src/fp_decimal/trigonometry.rs +++ b/packages/injective-math/src/fp_decimal/trigonometry.rs @@ -1,7 +1,7 @@ use crate::fp_decimal::FPDecimal; impl FPDecimal { - pub fn _cos(mut x: FPDecimal) -> FPDecimal { + pub(self) fn _cos(mut x: FPDecimal) -> FPDecimal { x = FPDecimal::_change_range(x); FPDecimal::_sin(FPDecimal::PI / FPDecimal::TWO - x) } @@ -14,7 +14,7 @@ impl FPDecimal { + (x.pow(FPDecimal::FOUR + FPDecimal::NINE) / (FPDecimal::FOUR + FPDecimal::NINE).factorial()) } - pub fn _sin(mut x: FPDecimal) -> FPDecimal { + pub(self) fn _sin(mut x: FPDecimal) -> FPDecimal { x = FPDecimal::_change_range(x); let pi_by_2 = FPDecimal::PI / FPDecimal::TWO; let pi_plus_pi_by_2 = FPDecimal::PI + FPDecimal::PI / FPDecimal::TWO; From 2ff258dc07b4187a7907d5d0dfd1c816b6e9c782 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Thu, 26 Oct 2023 17:19:49 -0400 Subject: [PATCH 19/26] minor improvement --- packages/injective-math/src/fp_decimal/trigonometry.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/trigonometry.rs b/packages/injective-math/src/fp_decimal/trigonometry.rs index 6035b5da..f8a23e14 100644 --- a/packages/injective-math/src/fp_decimal/trigonometry.rs +++ b/packages/injective-math/src/fp_decimal/trigonometry.rs @@ -10,8 +10,8 @@ impl FPDecimal { x - (x.pow(FPDecimal::THREE) / FPDecimal::THREE.factorial()) + (x.pow(FPDecimal::FIVE) / FPDecimal::FIVE.factorial()) - (x.pow(FPDecimal::SEVEN) / FPDecimal::SEVEN.factorial()) + (x.pow(FPDecimal::NINE) / FPDecimal::NINE.factorial()) - - (x.pow(FPDecimal::TWO + FPDecimal::NINE) / (FPDecimal::TWO + FPDecimal::NINE).factorial()) - + (x.pow(FPDecimal::FOUR + FPDecimal::NINE) / (FPDecimal::FOUR + FPDecimal::NINE).factorial()) + - (x.pow(FPDecimal::ELEVEN) / (FPDecimal::ELEVEN).factorial()) + + (x.pow(FPDecimal::THREE + FPDecimal::TEN) / (FPDecimal::THREE + FPDecimal::TEN).factorial()) } pub(self) fn _sin(mut x: FPDecimal) -> FPDecimal { From 4a980fe8e1268488198da24fb10877d876ccbbbb Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Fri, 27 Oct 2023 09:59:05 -0400 Subject: [PATCH 20/26] improved common checks --- packages/injective-math/src/fp_decimal/exp.rs | 9 +- .../injective-math/src/fp_decimal/from_str.rs | 1 + packages/injective-math/src/fp_decimal/log.rs | 136 +++++++++++------- 3 files changed, 85 insertions(+), 61 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 94781699..654168f2 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -706,17 +706,12 @@ impl FPDecimal { (&FPDecimal::log11, FPDecimal::ELEVEN), ]; for (log_fn, divisor) in base_checks { - if log_fn(exponent).is_some() { - let value = log_fn(exponent).unwrap(); + if let Some(value) = log_fn(exponent) { if self == divisor { return value; } } - if log_fn(self).is_some() { - let value = log_fn(self).unwrap(); - if FPDecimal::ONE / value == exponent { - return divisor; - } + if let Some(value) = log_fn(self) { if FPDecimal::ONE / value == exponent { return divisor; } diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs index f0a6d8fe..16760335 100644 --- a/packages/injective-math/src/fp_decimal/from_str.rs +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -56,6 +56,7 @@ mod tests { #[test] fn test_from_str_neg() { + //-0.69314718055994530943 assert_eq!((FPDecimal::ONE / FPDecimal::TWO).ln(), FPDecimal::must_from_str("-0.693147180435828445")); assert_eq!( (FPDecimal::ONE / FPDecimal::must_from_str("1.9")).ln(), diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 0961f78c..7bdc6c79 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -2,33 +2,6 @@ use crate::fp_decimal::{FPDecimal, U256}; impl FPDecimal { - fn _log_const(self) -> Option<(FPDecimal, u128)> { - if let Some(value) = self.log2() { - return Some((value, 2u128)); - } - - if let Some(value) = self.log_e() { - //NOTE: base e can't be represented by u128, so we use 27 in here - return Some((value, 27u128)); - } - if let Some(value) = self.log3() { - return Some((value, 3u128)); - } - if let Some(value) = self.log5() { - return Some((value, 5u128)); - } - if let Some(value) = self.log7() { - return Some((value, 7u128)); - } - if let Some(value) = self.log10() { - return Some((value, 10u128)); - } - if let Some(value) = self.log11() { - return Some((value, 11u128)); - } - None - } - pub(crate) fn log_e(self) -> Option { let e = FPDecimal::E; if self == FPDecimal::ONE { @@ -64,6 +37,10 @@ impl FPDecimal { if self == e * e * e * e * e * e * e * e * e * e { return Some(FPDecimal::TEN); } + if self == e * e * e * e * e * e * e * e * e * e * e { + return Some(FPDecimal::ELEVEN); + } + if self == FPDecimal::ONE / FPDecimal::E { return Some(-FPDecimal::ONE); } @@ -94,6 +71,9 @@ impl FPDecimal { if self == FPDecimal::ONE / (e * e * e * e * e * e * e * e * e * e) { return Some(-FPDecimal::TEN); } + if self == FPDecimal::ONE / (e * e * e * e * e * e * e * e * e * e * e) { + return Some(-FPDecimal::ELEVEN); + } None } @@ -131,6 +111,10 @@ impl FPDecimal { if self == FPDecimal::from(1024u128) { return Some(FPDecimal::TEN); } + if self == FPDecimal::from(2048u128) { + return Some(FPDecimal::ELEVEN); + } + if self == FPDecimal::ONE / FPDecimal::TWO { return Some(-FPDecimal::ONE); } @@ -161,6 +145,9 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(1024u128) { return Some(-FPDecimal::TEN); } + if self == FPDecimal::ONE / FPDecimal::from(2048u128) { + return Some(-FPDecimal::ELEVEN); + } None } @@ -198,6 +185,9 @@ impl FPDecimal { if self == FPDecimal::from(59049u128) { return Some(FPDecimal::TEN); } + if self == FPDecimal::from(177147u128) { + return Some(FPDecimal::ELEVEN); + } if self == FPDecimal::ONE / FPDecimal::THREE { return Some(-FPDecimal::ONE); @@ -229,6 +219,10 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(59049u128) { return Some(-FPDecimal::TEN); } + if self == FPDecimal::ONE / FPDecimal::from(177147u128) { + return Some(-FPDecimal::ELEVEN); + } + None } @@ -266,6 +260,10 @@ impl FPDecimal { if self == FPDecimal::from(9765625u128) { return Some(FPDecimal::TEN); } + if self == FPDecimal::from(48828125u128) { + return Some(FPDecimal::ELEVEN); + } + if self == FPDecimal::ONE / FPDecimal::FIVE { return Some(-FPDecimal::ONE); } @@ -296,6 +294,10 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(9765625u128) { return Some(-FPDecimal::TEN); } + if self == FPDecimal::ONE / FPDecimal::from(48828125u128) { + return Some(-FPDecimal::ELEVEN); + } + None } @@ -334,6 +336,9 @@ impl FPDecimal { if self == FPDecimal::from(282475249u128) { return Some(FPDecimal::TEN); } + if self == FPDecimal::from(1977326743u128) { + return Some(FPDecimal::ELEVEN); + } if self == FPDecimal::ONE / FPDecimal::SEVEN { return Some(-FPDecimal::ONE); } @@ -364,6 +369,10 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(282475249u128) { return Some(-FPDecimal::TEN); } + if self == FPDecimal::ONE / FPDecimal::from(1977326743u128) { + return Some(-FPDecimal::ELEVEN); + } + None } @@ -401,6 +410,9 @@ impl FPDecimal { if self == FPDecimal::from(10_000_000_000u128) { return Some(FPDecimal::TEN); } + if self == FPDecimal::from(100_000_000_000u128) { + return Some(FPDecimal::ELEVEN); + } if self == FPDecimal::ONE / FPDecimal::TEN { return Some(-FPDecimal::ONE); @@ -432,6 +444,9 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(10_000_000_000u128) { return Some(-FPDecimal::TEN); } + if self == FPDecimal::ONE / FPDecimal::from(100_000_000_000u128) { + return Some(-FPDecimal::ELEVEN); + } None } @@ -470,6 +485,10 @@ impl FPDecimal { if self == FPDecimal::from(25937424601u128) { return Some(FPDecimal::TEN); } + if self == FPDecimal::from(285311670611u128) { + return Some(FPDecimal::ELEVEN); + } + if self == FPDecimal::ONE / FPDecimal::ELEVEN { return Some(-FPDecimal::ONE); } @@ -500,6 +519,10 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(25937424601u128) { return Some(-FPDecimal::TEN); } + if self == FPDecimal::ONE / FPDecimal::from(285311670611u128) { + return Some(-FPDecimal::ELEVEN); + } + None } @@ -517,7 +540,37 @@ impl FPDecimal { a.ln() / base.ln() } - #[allow(clippy::many_single_char_names)] + pub fn log(&self, base: FPDecimal) -> FPDecimal { + assert!(base > FPDecimal::ZERO); + if *self == FPDecimal::ONE { + return FPDecimal::ZERO; + } + if *self == FPDecimal::ZERO { + // FIXME should be an undefined, not sure if it will be better to just add assert!(b>0) + return FPDecimal::SMALLEST_PRECISION; + } + + if base == FPDecimal::E { + return self.ln(); + } + + let base_checks: Vec<&dyn Fn(FPDecimal) -> Option> = vec![ + &FPDecimal::log_e, + &FPDecimal::log2, + &FPDecimal::log3, + &FPDecimal::log5, + &FPDecimal::log7, + &FPDecimal::log10, + &FPDecimal::log11, + ]; + for log_fn in base_checks { + if let (Some(numerator), Some(denominator)) = (log_fn(*self), log_fn(base)) { + return numerator / denominator; + } + } + FPDecimal::_log(*self, base) + } + fn _two_agm(mut a0: FPDecimal, mut b0: FPDecimal, tol: FPDecimal) -> FPDecimal { loop { if (a0 - b0).abs() < tol { @@ -536,6 +589,7 @@ impl FPDecimal { // m =8, 2**8=256; // m=16, 2**16=65536 // m=32, 2**32=4294967296 + // m=64, 2**64=18446744073709551616 // m=128, 2**128=340282366920938463463374607431768211456 let two_pow_m = FPDecimal::from(4294967296u128); let s = *self * two_pow_m; @@ -629,32 +683,6 @@ impl FPDecimal { } self._ln() } - - pub fn log(&self, base: FPDecimal) -> FPDecimal { - assert!(base > FPDecimal::ZERO); - if *self == FPDecimal::ONE { - return FPDecimal::ZERO; - } - if *self == FPDecimal::ZERO { - // FIXME should be an undefined, not sure if it will be better to just add assert!(b>0) - return FPDecimal::SMALLEST_PRECISION; - } - - if base == FPDecimal::E { - return self.ln(); - } - let numerator = self._log_const(); - let denominator = base._log_const(); - match (numerator, denominator) { - (Some((n, nbase)), Some((d, dbase))) => { - if dbase == nbase { - return n / d; - } - FPDecimal::_log(*self, base) - } - (_, _) => FPDecimal::_log(*self, base), - } - } } #[cfg(test)] From e4c7ed137978f0df1044846c73afdc1d1656487b Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Fri, 27 Oct 2023 11:36:03 -0400 Subject: [PATCH 21/26] minor improvements --- packages/injective-math/src/fp_decimal/exp.rs | 1569 +++++++++++------ packages/injective-math/src/fp_decimal/log.rs | 146 ++ 2 files changed, 1147 insertions(+), 568 deletions(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 654168f2..581523fe 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -21,7 +21,7 @@ impl FPDecimal { FPDecimal::EIGHT, FPDecimal::NINE, FPDecimal::TEN, - FPDecimal::must_from_str("11"), + FPDecimal::ELEVEN, FPDecimal::must_from_str("12"), FPDecimal::must_from_str("13"), FPDecimal::must_from_str("14"), @@ -53,6 +53,993 @@ impl FPDecimal { } // e^(a) + fn two_pow(exponent: FPDecimal) -> Option { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::TWO); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::FOUR); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::EIGHT); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(16u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(32u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(64u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(128u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(256u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(512u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(1024u128)); + } + if exponent == FPDecimal::ELEVEN { + return Some(FPDecimal::from(2048u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(4096u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(8192u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(16384u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(32768u128)); + } + + if FPDecimal::ONE.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE); + } + if FPDecimal::TWO.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::TWO); + } + if FPDecimal::THREE.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::THREE); + } + if FPDecimal::FOUR.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::FOUR); + } + if FPDecimal::FIVE.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::FIVE); + } + if FPDecimal::SIX.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::SIX); + } + if FPDecimal::SEVEN.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::SEVEN); + } + if FPDecimal::EIGHT.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::EIGHT); + } + if FPDecimal::NINE.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::NINE); + } + if FPDecimal::TEN.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::TEN); + } + if FPDecimal::ELEVEN.log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ELEVEN); + } + if FPDecimal::from(12u128).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::from(12u128)); + } + if FPDecimal::from(13u128).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::from(13u128)); + } + if FPDecimal::from(14u128).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::from(14u128)); + } + if FPDecimal::from(15u128).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::from(15u128)); + } + + if (FPDecimal::ONE / FPDecimal::TWO).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::TWO); + } + if (FPDecimal::ONE / FPDecimal::THREE).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::THREE); + } + if (FPDecimal::ONE / FPDecimal::FOUR).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::FOUR); + } + if (FPDecimal::ONE / FPDecimal::FIVE).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::FIVE); + } + if (FPDecimal::ONE / FPDecimal::SIX).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::SIX); + } + if (FPDecimal::ONE / FPDecimal::SEVEN).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::SEVEN); + } + if (FPDecimal::ONE / FPDecimal::EIGHT).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::EIGHT); + } + if (FPDecimal::ONE / FPDecimal::NINE).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::NINE); + } + if (FPDecimal::ONE / FPDecimal::TEN).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::TEN); + } + if (FPDecimal::ONE / FPDecimal::ELEVEN).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::ELEVEN); + } + if (FPDecimal::ONE / FPDecimal::from(12u128)).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::from(12u128)); + } + if (FPDecimal::ONE / FPDecimal::from(13u128)).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::from(13u128)); + } + if (FPDecimal::ONE / FPDecimal::from(14u128)).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::from(14u128)); + } + if (FPDecimal::ONE / FPDecimal::from(15u128)).log2().is_some_and(|x| x == exponent) { + return Some(FPDecimal::ONE / FPDecimal::from(15u128)); + } + + if exponent == -FPDecimal::TWO { + return Some(FPDecimal::ONE / FPDecimal::FOUR); + } + if exponent == -FPDecimal::THREE { + return Some(FPDecimal::ONE / FPDecimal::EIGHT); + } + if exponent == -FPDecimal::FOUR { + return Some(FPDecimal::ONE / FPDecimal::from(16u128)); + } + if exponent == -FPDecimal::FIVE { + return Some(FPDecimal::ONE / FPDecimal::from(32u128)); + } + if exponent == -FPDecimal::SIX { + return Some(FPDecimal::ONE / FPDecimal::from(64u128)); + } + if exponent == -FPDecimal::SEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(128u128)); + } + if exponent == -FPDecimal::EIGHT { + return Some(FPDecimal::ONE / FPDecimal::from(256u128)); + } + if exponent == -FPDecimal::NINE { + return Some(FPDecimal::ONE / FPDecimal::from(512u128)); + } + if exponent == -FPDecimal::TEN { + return Some(FPDecimal::ONE / FPDecimal::from(1024u128)); + } + if exponent == -FPDecimal::ELEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(2048u128)); + } + if exponent == -FPDecimal::from(12u128) { + return Some(FPDecimal::ONE / FPDecimal::from(4096u128)); + } + if exponent == -FPDecimal::from(13u128) { + return Some(FPDecimal::ONE / FPDecimal::from(8192u128)); + } + if exponent == -FPDecimal::from(14u128) { + return Some(FPDecimal::ONE / FPDecimal::from(16384u128)); + } + if exponent == -FPDecimal::from(15u128) { + return Some(FPDecimal::ONE / FPDecimal::from(32768u128)); + } + + None + } + + fn e_pow(exponent: FPDecimal) -> Option { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::E); + } + if exponent == FPDecimal::ONE.ln() { + return Some(FPDecimal::ONE); + } + if exponent == FPDecimal::TWO.ln() { + return Some(FPDecimal::TWO); + } + if exponent == FPDecimal::THREE.ln() { + return Some(FPDecimal::THREE); + } + if exponent == FPDecimal::FOUR.ln() { + return Some(FPDecimal::FOUR); + } + if exponent == FPDecimal::FIVE.ln() { + return Some(FPDecimal::FIVE); + } + if exponent == FPDecimal::SIX.ln() { + return Some(FPDecimal::SIX); + } + if exponent == FPDecimal::SEVEN.ln() { + return Some(FPDecimal::SEVEN); + } + if exponent == FPDecimal::EIGHT.ln() { + return Some(FPDecimal::EIGHT); + } + if exponent == FPDecimal::NINE.ln() { + return Some(FPDecimal::NINE); + } + if exponent == FPDecimal::TEN.ln() { + return Some(FPDecimal::TEN); + } + if exponent == FPDecimal::ELEVEN.ln() { + return Some(FPDecimal::ELEVEN); + } + if exponent == FPDecimal::from(12u128).ln() { + return Some(FPDecimal::from(12u128)); + } + if exponent == FPDecimal::from(13u128).ln() { + return Some(FPDecimal::from(13u128)); + } + if exponent == FPDecimal::from(14u128).ln() { + return Some(FPDecimal::from(14u128)); + } + if exponent == FPDecimal::from(15u128).ln() { + return Some(FPDecimal::from(15u128)); + } + + if exponent == (FPDecimal::ONE / FPDecimal::TWO).ln() { + return Some(FPDecimal::ONE / FPDecimal::TWO); + } + if exponent == (FPDecimal::ONE / FPDecimal::THREE).ln() { + return Some(FPDecimal::ONE / FPDecimal::THREE); + } + if exponent == (FPDecimal::ONE / FPDecimal::FOUR).ln() { + return Some(FPDecimal::ONE / FPDecimal::FOUR); + } + if exponent == (FPDecimal::ONE / FPDecimal::FIVE).ln() { + return Some(FPDecimal::ONE / FPDecimal::FIVE); + } + if exponent == (FPDecimal::ONE / FPDecimal::SIX).ln() { + return Some(FPDecimal::ONE / FPDecimal::SIX); + } + if exponent == (FPDecimal::ONE / FPDecimal::SEVEN).ln() { + return Some(FPDecimal::ONE / FPDecimal::SEVEN); + } + if exponent == (FPDecimal::ONE / FPDecimal::EIGHT).ln() { + return Some(FPDecimal::ONE / FPDecimal::EIGHT); + } + if exponent == (FPDecimal::ONE / FPDecimal::NINE).ln() { + return Some(FPDecimal::ONE / FPDecimal::NINE); + } + if exponent == (FPDecimal::ONE / FPDecimal::TEN).ln() { + return Some(FPDecimal::ONE / FPDecimal::TEN); + } + if exponent == (FPDecimal::ONE / FPDecimal::ELEVEN).ln() { + return Some(FPDecimal::ONE / FPDecimal::ELEVEN); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(12u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(12u128)); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(13u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(13u128)); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(14u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(14u128)); + } + if exponent == (FPDecimal::ONE / FPDecimal::from(15u128)).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(15u128)); + } + + if exponent == -FPDecimal::ONE { + return Some(FPDecimal::ONE / FPDecimal::E); + } + if exponent == -FPDecimal::ONE.ln() { + return Some(FPDecimal::ONE); + } + if exponent == FPDecimal::TWO.ln() { + return Some(FPDecimal::ONE / FPDecimal::TWO); + } + if exponent == -FPDecimal::THREE.ln() { + return Some(FPDecimal::ONE / FPDecimal::THREE); + } + if exponent == -FPDecimal::FOUR.ln() { + return Some(FPDecimal::ONE / FPDecimal::FOUR); + } + if exponent == -FPDecimal::FIVE.ln() { + return Some(FPDecimal::ONE / FPDecimal::FIVE); + } + if exponent == -FPDecimal::SIX.ln() { + return Some(FPDecimal::ONE / FPDecimal::SIX); + } + if exponent == -FPDecimal::SEVEN.ln() { + return Some(FPDecimal::ONE / FPDecimal::SEVEN); + } + if exponent == -FPDecimal::EIGHT.ln() { + return Some(FPDecimal::ONE / FPDecimal::EIGHT); + } + if exponent == -FPDecimal::NINE.ln() { + return Some(FPDecimal::ONE / FPDecimal::NINE); + } + if exponent == -FPDecimal::TEN.ln() { + return Some(FPDecimal::ONE / FPDecimal::TEN); + } + if exponent == -FPDecimal::ELEVEN.ln() { + return Some(FPDecimal::ONE / FPDecimal::ELEVEN); + } + if exponent == -FPDecimal::from(12u128).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(12u128)); + } + if exponent == -FPDecimal::from(13u128).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(13u128)); + } + if exponent == -FPDecimal::from(14u128).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(14u128)); + } + if exponent == -FPDecimal::from(15u128).ln() { + return Some(FPDecimal::ONE / FPDecimal::from(15u128)); + } + + if exponent == -(FPDecimal::ONE / FPDecimal::TWO).ln() { + return Some(FPDecimal::TWO); + } + if exponent == -(FPDecimal::ONE / FPDecimal::THREE).ln() { + return Some(FPDecimal::THREE); + } + if exponent == -(FPDecimal::ONE / FPDecimal::FOUR).ln() { + return Some(FPDecimal::FOUR); + } + if exponent == -(FPDecimal::ONE / FPDecimal::FIVE).ln() { + return Some(FPDecimal::FIVE); + } + if exponent == -(FPDecimal::ONE / FPDecimal::SIX).ln() { + return Some(FPDecimal::SIX); + } + if exponent == -(FPDecimal::ONE / FPDecimal::SEVEN).ln() { + return Some(FPDecimal::SEVEN); + } + if exponent == -(FPDecimal::ONE / FPDecimal::EIGHT).ln() { + return Some(FPDecimal::EIGHT); + } + if exponent == -(FPDecimal::ONE / FPDecimal::NINE).ln() { + return Some(FPDecimal::NINE); + } + if exponent == -(FPDecimal::ONE / FPDecimal::TEN).ln() { + return Some(FPDecimal::TEN); + } + if exponent == -(FPDecimal::ONE / FPDecimal::ELEVEN).ln() { + return Some(FPDecimal::ELEVEN); + } + if exponent == -(FPDecimal::ONE / FPDecimal::from(12u128)).ln() { + return Some(FPDecimal::from(12u128)); + } + if exponent == -(FPDecimal::ONE / FPDecimal::from(13u128)).ln() { + return Some(FPDecimal::from(13u128)); + } + if exponent == -(FPDecimal::ONE / FPDecimal::from(14u128)).ln() { + return Some(FPDecimal::from(14u128)); + } + if exponent == -(FPDecimal::ONE / FPDecimal::from(15u128)).ln() { + return Some(FPDecimal::from(15u128)); + } + None + } + + fn three_pow(exponent: FPDecimal) -> Option { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::THREE); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::NINE); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(27u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(81u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(243u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(729u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(2187u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(6561u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(19683u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(59049u128)); + } + if exponent == FPDecimal::ELEVEN { + return Some(FPDecimal::from(177147u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(531441u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(1594323u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(4782969u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(14348907u128)); + } + + if exponent == -FPDecimal::ONE { + return Some(FPDecimal::ONE / FPDecimal::THREE); + } + if exponent == -FPDecimal::TWO { + return Some(FPDecimal::ONE / FPDecimal::NINE); + } + if exponent == -FPDecimal::THREE { + return Some(FPDecimal::ONE / FPDecimal::from(27u128)); + } + if exponent == -FPDecimal::FOUR { + return Some(FPDecimal::ONE / FPDecimal::from(81u128)); + } + if exponent == -FPDecimal::FIVE { + return Some(FPDecimal::ONE / FPDecimal::from(243u128)); + } + if exponent == -FPDecimal::SIX { + return Some(FPDecimal::ONE / FPDecimal::from(729u128)); + } + if exponent == -FPDecimal::SEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(2187u128)); + } + if exponent == -FPDecimal::EIGHT { + return Some(FPDecimal::ONE / FPDecimal::from(6561u128)); + } + if exponent == -FPDecimal::NINE { + return Some(FPDecimal::ONE / FPDecimal::from(19683u128)); + } + if exponent == -FPDecimal::TEN { + return Some(FPDecimal::ONE / FPDecimal::from(59049u128)); + } + if exponent == -FPDecimal::ELEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(177147u128)); + } + if exponent == -FPDecimal::from(12u128) { + return Some(FPDecimal::ONE / FPDecimal::from(531441u128)); + } + if exponent == -FPDecimal::from(13u128) { + return Some(FPDecimal::ONE / FPDecimal::from(1594323u128)); + } + if exponent == -FPDecimal::from(14u128) { + return Some(FPDecimal::ONE / FPDecimal::from(4782969u128)); + } + if exponent == -FPDecimal::from(15u128) { + return Some(FPDecimal::ONE / FPDecimal::from(14348907u128)); + } + None + } + + fn five_pow(exponent: FPDecimal) -> Option { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::FIVE); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::from(25u128)); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(125u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(625u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(3125u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(15625u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(78125u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(390625u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(1953125u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(9765625u128)); + } + if exponent == FPDecimal::ELEVEN { + return Some(FPDecimal::from(48828125u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(244140625u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(1220703125u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(6103515625u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(30517578125u128)); + } + + if exponent == -FPDecimal::ONE { + return Some(FPDecimal::ONE / FPDecimal::FIVE); + } + if exponent == -FPDecimal::TWO { + return Some(FPDecimal::ONE / FPDecimal::from(25u128)); + } + if exponent == -FPDecimal::THREE { + return Some(FPDecimal::ONE / FPDecimal::from(125u128)); + } + if exponent == -FPDecimal::FOUR { + return Some(FPDecimal::ONE / FPDecimal::from(625u128)); + } + if exponent == -FPDecimal::FIVE { + return Some(FPDecimal::ONE / FPDecimal::from(3125u128)); + } + if exponent == -FPDecimal::SIX { + return Some(FPDecimal::ONE / FPDecimal::from(15625u128)); + } + if exponent == -FPDecimal::SEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(78125u128)); + } + if exponent == -FPDecimal::EIGHT { + return Some(FPDecimal::ONE / FPDecimal::from(390625u128)); + } + if exponent == -FPDecimal::NINE { + return Some(FPDecimal::ONE / FPDecimal::from(1953125u128)); + } + if exponent == -FPDecimal::TEN { + return Some(FPDecimal::ONE / FPDecimal::from(9765625u128)); + } + if exponent == -FPDecimal::ELEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(48828125u128)); + } + if exponent == -FPDecimal::from(12u128) { + return Some(FPDecimal::ONE / FPDecimal::from(244140625u128)); + } + if exponent == -FPDecimal::from(13u128) { + return Some(FPDecimal::ONE / FPDecimal::from(1220703125u128)); + } + if exponent == -FPDecimal::from(14u128) { + return Some(FPDecimal::ONE / FPDecimal::from(6103515625u128)); + } + if exponent == -FPDecimal::from(15u128) { + return Some(FPDecimal::ONE / FPDecimal::from(30517578125u128)); + } + None + } + + fn seven_pow(exponent: FPDecimal) -> Option { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::SEVEN); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::from(49u128)); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(343u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(2401u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(16807u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(117649u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(823543u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(5764801u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(40353607u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(282475249u128)); + } + if exponent == FPDecimal::ELEVEN { + return Some(FPDecimal::from(1977326743u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(13841287201u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(96889010407u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(678223072849u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(4747561509943u128)); + } + if exponent == -FPDecimal::ONE { + return Some(FPDecimal::ONE / FPDecimal::SEVEN); + } + if exponent == -FPDecimal::TWO { + return Some(FPDecimal::ONE / FPDecimal::from(49u128)); + } + if exponent == -FPDecimal::THREE { + return Some(FPDecimal::ONE / FPDecimal::from(343u128)); + } + if exponent == -FPDecimal::FOUR { + return Some(FPDecimal::ONE / FPDecimal::from(2401u128)); + } + if exponent == -FPDecimal::FIVE { + return Some(FPDecimal::ONE / FPDecimal::from(16807u128)); + } + if exponent == -FPDecimal::SIX { + return Some(FPDecimal::ONE / FPDecimal::from(117649u128)); + } + if exponent == -FPDecimal::SEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(823543u128)); + } + if exponent == -FPDecimal::EIGHT { + return Some(FPDecimal::ONE / FPDecimal::from(5764801u128)); + } + if exponent == -FPDecimal::NINE { + return Some(FPDecimal::ONE / FPDecimal::from(40353607u128)); + } + if exponent == -FPDecimal::TEN { + return Some(FPDecimal::ONE / FPDecimal::from(282475249u128)); + } + if exponent == -FPDecimal::ELEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(1977326743u128)); + } + if exponent == -FPDecimal::from(12u128) { + return Some(FPDecimal::ONE / FPDecimal::from(13841287201u128)); + } + if exponent == -FPDecimal::from(13u128) { + return Some(FPDecimal::ONE / FPDecimal::from(96889010407u128)); + } + if exponent == -FPDecimal::from(14u128) { + return Some(FPDecimal::ONE / FPDecimal::from(678223072849u128)); + } + if exponent == -FPDecimal::from(15u128) { + return Some(FPDecimal::ONE / FPDecimal::from(4747561509943u128)); + } + + None + } + + fn ten_pow(exponent: FPDecimal) -> Option { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::from(10u128)); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::from(100u128)); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(1000u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(10000u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(100000u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(1000000u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(10000000u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(100000000u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(1000000000u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(10000000000u128)); + } + if exponent == FPDecimal::ELEVEN { + return Some(FPDecimal::from(100000000000u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(1000000000000u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(10000000000000u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(100000000000000u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(1000000000000000u128)); + } + if exponent == FPDecimal::from(16u128) { + return Some(FPDecimal::from(10000000000000000u128)); + } + if exponent == FPDecimal::from(17u128) { + return Some(FPDecimal::from(100000000000000000u128)); + } + if exponent == FPDecimal::from(18u128) { + return Some(FPDecimal::from(1000000000000000000u128)); + } + if exponent == FPDecimal::from(19u128) { + return Some(FPDecimal::from(10000000000000000000u128)); + } + if exponent == FPDecimal::from(20u128) { + return Some(FPDecimal::from(100000000000000000000u128)); + } + if exponent == FPDecimal::NEGATIVE_ONE { + return Some(FPDecimal::from_str("0.1").unwrap()); + } + if exponent == FPDecimal::from_str("-2").unwrap() { + return Some(FPDecimal::from_str("0.01").unwrap()); + } + if exponent == FPDecimal::from_str("-3").unwrap() { + return Some(FPDecimal::from_str("0.001").unwrap()); + } + if exponent == FPDecimal::from_str("-4").unwrap() { + return Some(FPDecimal::from_str("0.0001").unwrap()); + } + if exponent == FPDecimal::from_str("-5").unwrap() { + return Some(FPDecimal::from_str("0.00001").unwrap()); + } + if exponent == FPDecimal::from_str("-6").unwrap() { + return Some(FPDecimal::from_str("0.000001").unwrap()); + } + if exponent == FPDecimal::from_str("-7").unwrap() { + return Some(FPDecimal::from_str("0.0000001").unwrap()); + } + if exponent == FPDecimal::from_str("-8").unwrap() { + return Some(FPDecimal::from_str("0.00000001").unwrap()); + } + if exponent == FPDecimal::from_str("-9").unwrap() { + return Some(FPDecimal::from_str("0.000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-10").unwrap() { + return Some(FPDecimal::from_str("0.0000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-11").unwrap() { + return Some(FPDecimal::from_str("0.00000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-12").unwrap() { + return Some(FPDecimal::from_str("0.000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-13").unwrap() { + return Some(FPDecimal::from_str("0.0000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-14").unwrap() { + return Some(FPDecimal::from_str("0.00000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-15").unwrap() { + return Some(FPDecimal::from_str("0.000000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-16").unwrap() { + return Some(FPDecimal::from_str("0.0000000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-17").unwrap() { + return Some(FPDecimal::from_str("0.00000000000000001").unwrap()); + } + if exponent == FPDecimal::from_str("-18").unwrap() { + return Some(FPDecimal::from_str("0.000000000000000001").unwrap()); + } + if exponent < FPDecimal::from_str("-18").unwrap() { + return Some(FPDecimal::ZERO); + } + if exponent == FPDecimal::from(21u128) { + return Some(FPDecimal::from(1000000000000000000000u128)); + } + if exponent == FPDecimal::from(22u128) { + return Some(FPDecimal::from(10000000000000000000000u128)); + } + if exponent == FPDecimal::from(23u128) { + return Some(FPDecimal::from(100000000000000000000000u128)); + } + if exponent == FPDecimal::from(24u128) { + return Some(FPDecimal::from(1000000000000000000000000u128)); + } + if exponent == FPDecimal::from(25u128) { + return Some(FPDecimal::from(10000000000000000000000000u128)); + } + if exponent == FPDecimal::from(26u128) { + return Some(FPDecimal::from(100000000000000000000000000u128)); + } + if exponent == FPDecimal::from(27u128) { + return Some(FPDecimal::from(1000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(28u128) { + return Some(FPDecimal::from(10000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(29u128) { + return Some(FPDecimal::from(100000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(30u128) { + return Some(FPDecimal::from(1000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(31u128) { + return Some(FPDecimal::from(10000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(32u128) { + return Some(FPDecimal::from(100000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(33u128) { + return Some(FPDecimal::from(1000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(34u128) { + return Some(FPDecimal::from(10000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(35u128) { + return Some(FPDecimal::from(100000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(36u128) { + return Some(FPDecimal::from(1000000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(37u128) { + return Some(FPDecimal::from(10000000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(38u128) { + return Some(FPDecimal::from(100000000000000000000000000000000000000u128)); + } + if exponent == FPDecimal::from(39u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(40u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(41u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(42u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(43u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(44u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(45u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(46u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(47u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(48u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(49u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(50u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(51u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(52u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(53u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(54u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(55u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(56u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(57u128) { + return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(58u128) { + return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000000").unwrap()); + } + if exponent == FPDecimal::from(59u128) { + return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000000").unwrap()); + } + None + } + + fn eleven_pow(exponent: FPDecimal) -> Option { + if exponent == FPDecimal::ONE { + return Some(FPDecimal::ELEVEN); + } + if exponent == FPDecimal::TWO { + return Some(FPDecimal::from(121u128)); + } + if exponent == FPDecimal::THREE { + return Some(FPDecimal::from(1331u128)); + } + if exponent == FPDecimal::FOUR { + return Some(FPDecimal::from(14641u128)); + } + if exponent == FPDecimal::FIVE { + return Some(FPDecimal::from(161051u128)); + } + if exponent == FPDecimal::SIX { + return Some(FPDecimal::from(1771561u128)); + } + if exponent == FPDecimal::SEVEN { + return Some(FPDecimal::from(19487171u128)); + } + if exponent == FPDecimal::EIGHT { + return Some(FPDecimal::from(214358881u128)); + } + if exponent == FPDecimal::NINE { + return Some(FPDecimal::from(2357947691u128)); + } + if exponent == FPDecimal::TEN { + return Some(FPDecimal::from(25937424601u128)); + } + if exponent == FPDecimal::ELEVEN { + return Some(FPDecimal::from(285311670611u128)); + } + if exponent == FPDecimal::from(12u128) { + return Some(FPDecimal::from(3138428376721u128)); + } + if exponent == FPDecimal::from(13u128) { + return Some(FPDecimal::from(34522712143931u128)); + } + if exponent == FPDecimal::from(14u128) { + return Some(FPDecimal::from(379749833583241u128)); + } + if exponent == FPDecimal::from(15u128) { + return Some(FPDecimal::from(4177248169415651u128)); + } + if exponent == -FPDecimal::ONE { + return Some(FPDecimal::ONE / FPDecimal::ELEVEN); + } + if exponent == -FPDecimal::TWO { + return Some(FPDecimal::ONE / FPDecimal::from(121u128)); + } + if exponent == -FPDecimal::THREE { + return Some(FPDecimal::ONE / FPDecimal::from(1331u128)); + } + if exponent == -FPDecimal::FOUR { + return Some(FPDecimal::ONE / FPDecimal::from(14641u128)); + } + if exponent == -FPDecimal::FIVE { + return Some(FPDecimal::ONE / FPDecimal::from(161051u128)); + } + if exponent == -FPDecimal::SIX { + return Some(FPDecimal::ONE / FPDecimal::from(1771561u128)); + } + if exponent == -FPDecimal::SEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(19487171u128)); + } + if exponent == -FPDecimal::EIGHT { + return Some(FPDecimal::ONE / FPDecimal::from(214358881u128)); + } + if exponent == -FPDecimal::NINE { + return Some(FPDecimal::ONE / FPDecimal::from(2357947691u128)); + } + if exponent == -FPDecimal::TEN { + return Some(FPDecimal::ONE / FPDecimal::from(25937424601u128)); + } + if exponent == -FPDecimal::ELEVEN { + return Some(FPDecimal::ONE / FPDecimal::from(285311670611u128)); + } + if exponent == -FPDecimal::from(12u128) { + return Some(FPDecimal::ONE / FPDecimal::from(3138428376721u128)); + } + if exponent == -FPDecimal::from(13u128) { + return Some(FPDecimal::ONE / FPDecimal::from(34522712143931u128)); + } + if exponent == -FPDecimal::from(14u128) { + return Some(FPDecimal::ONE / FPDecimal::from(379749833583241u128)); + } + if exponent == -FPDecimal::from(15u128) { + return Some(FPDecimal::ONE / FPDecimal::from(4177248169415651u128)); + } + + None + } + pub fn pow(self, exponent: FPDecimal) -> FPDecimal { if self.is_zero() { return self; @@ -69,573 +1056,19 @@ impl FPDecimal { return Some(FPDecimal::ONE); } - if base == FPDecimal::E { - if exponent == FPDecimal::ONE { - return Some(base); - } - if exponent == FPDecimal::ONE.ln() { - return Some(FPDecimal::ONE); - } - if exponent == FPDecimal::TWO.ln() { - return Some(FPDecimal::TWO); - } - if exponent == FPDecimal::THREE.ln() { - return Some(FPDecimal::THREE); - } - if exponent == FPDecimal::FOUR.ln() { - return Some(FPDecimal::FOUR); - } - if exponent == FPDecimal::FIVE.ln() { - return Some(FPDecimal::FIVE); - } - if exponent == FPDecimal::SIX.ln() { - return Some(FPDecimal::SIX); - } - if exponent == FPDecimal::SEVEN.ln() { - return Some(FPDecimal::SEVEN); - } - if exponent == FPDecimal::EIGHT.ln() { - return Some(FPDecimal::EIGHT); - } - if exponent == FPDecimal::NINE.ln() { - return Some(FPDecimal::NINE); - } - if exponent == FPDecimal::TEN.ln() { - return Some(FPDecimal::TEN); - } - if exponent == FPDecimal::ELEVEN.ln() { - return Some(FPDecimal::ELEVEN); - } - if exponent == FPDecimal::from(12u128).ln() { - return Some(FPDecimal::from(12u128)); - } - if exponent == FPDecimal::from(13u128).ln() { - return Some(FPDecimal::from(13u128)); - } - if exponent == FPDecimal::from(14u128).ln() { - return Some(FPDecimal::from(14u128)); - } - if exponent == FPDecimal::from(15u128).ln() { - return Some(FPDecimal::from(15u128)); - } - - if exponent == (FPDecimal::ONE / FPDecimal::TWO).ln() { - return Some(FPDecimal::ONE / FPDecimal::TWO); - } - if exponent == (FPDecimal::ONE / FPDecimal::THREE).ln() { - return Some(FPDecimal::ONE / FPDecimal::THREE); - } - if exponent == (FPDecimal::ONE / FPDecimal::FOUR).ln() { - return Some(FPDecimal::ONE / FPDecimal::FOUR); - } - if exponent == (FPDecimal::ONE / FPDecimal::FIVE).ln() { - return Some(FPDecimal::ONE / FPDecimal::FIVE); - } - if exponent == (FPDecimal::ONE / FPDecimal::SIX).ln() { - return Some(FPDecimal::ONE / FPDecimal::SIX); - } - if exponent == (FPDecimal::ONE / FPDecimal::SEVEN).ln() { - return Some(FPDecimal::ONE / FPDecimal::SEVEN); - } - if exponent == (FPDecimal::ONE / FPDecimal::EIGHT).ln() { - return Some(FPDecimal::ONE / FPDecimal::EIGHT); - } - if exponent == (FPDecimal::ONE / FPDecimal::NINE).ln() { - return Some(FPDecimal::ONE / FPDecimal::NINE); - } - if exponent == (FPDecimal::ONE / FPDecimal::TEN).ln() { - return Some(FPDecimal::ONE / FPDecimal::TEN); - } - if exponent == (FPDecimal::ONE / FPDecimal::ELEVEN).ln() { - return Some(FPDecimal::ONE / FPDecimal::ELEVEN); - } - if exponent == (FPDecimal::ONE / FPDecimal::from(12u128)).ln() { - return Some(FPDecimal::ONE / FPDecimal::from(12u128)); - } - if exponent == (FPDecimal::ONE / FPDecimal::from(13u128)).ln() { - return Some(FPDecimal::ONE / FPDecimal::from(13u128)); - } - if exponent == (FPDecimal::ONE / FPDecimal::from(14u128)).ln() { - return Some(FPDecimal::ONE / FPDecimal::from(14u128)); - } - if exponent == (FPDecimal::ONE / FPDecimal::from(15u128)).ln() { - return Some(FPDecimal::ONE / FPDecimal::from(15u128)); - } - } - - if base == FPDecimal::TWO { - if exponent == FPDecimal::ONE { - return Some(FPDecimal::TWO); - } - if exponent == FPDecimal::TWO { - return Some(FPDecimal::FOUR); - } - if exponent == FPDecimal::THREE { - return Some(FPDecimal::EIGHT); - } - if exponent == FPDecimal::FOUR { - return Some(FPDecimal::from(16u128)); - } - if exponent == FPDecimal::FIVE { - return Some(FPDecimal::from(32u128)); - } - if exponent == FPDecimal::SIX { - return Some(FPDecimal::from(64u128)); - } - if exponent == FPDecimal::SEVEN { - return Some(FPDecimal::from(128u128)); - } - if exponent == FPDecimal::EIGHT { - return Some(FPDecimal::from(256u128)); - } - if exponent == FPDecimal::NINE { - return Some(FPDecimal::from(512u128)); - } - if exponent == FPDecimal::TEN { - return Some(FPDecimal::from(1024u128)); - } - if exponent == FPDecimal::ELEVEN { - return Some(FPDecimal::from(2048u128)); - } - if exponent == FPDecimal::from(12u128) { - return Some(FPDecimal::from(4096u128)); - } - if exponent == FPDecimal::from(13u128) { - return Some(FPDecimal::from(8192u128)); - } - if exponent == FPDecimal::from(14u128) { - return Some(FPDecimal::from(16384u128)); - } - if exponent == FPDecimal::from(15u128) { - return Some(FPDecimal::from(32768u128)); - } - } - if base == FPDecimal::THREE { - if exponent == FPDecimal::ONE { - return Some(FPDecimal::THREE); - } - if exponent == FPDecimal::TWO { - return Some(FPDecimal::NINE); - } - if exponent == FPDecimal::THREE { - return Some(FPDecimal::from(27u128)); - } - if exponent == FPDecimal::FOUR { - return Some(FPDecimal::from(81u128)); - } - if exponent == FPDecimal::FIVE { - return Some(FPDecimal::from(243u128)); - } - if exponent == FPDecimal::SIX { - return Some(FPDecimal::from(729u128)); - } - if exponent == FPDecimal::SEVEN { - return Some(FPDecimal::from(2187u128)); - } - if exponent == FPDecimal::EIGHT { - return Some(FPDecimal::from(6561u128)); - } - if exponent == FPDecimal::NINE { - return Some(FPDecimal::from(19683u128)); - } - if exponent == FPDecimal::TEN { - return Some(FPDecimal::from(59049u128)); - } - if exponent == FPDecimal::ELEVEN { - return Some(FPDecimal::from(177147u128)); - } - if exponent == FPDecimal::from(12u128) { - return Some(FPDecimal::from(531441u128)); - } - if exponent == FPDecimal::from(13u128) { - return Some(FPDecimal::from(1594323u128)); - } - if exponent == FPDecimal::from(14u128) { - return Some(FPDecimal::from(4782969u128)); - } - if exponent == FPDecimal::from(15u128) { - return Some(FPDecimal::from(14348907u128)); - } - } - - if base == FPDecimal::FIVE { - if exponent == FPDecimal::ONE { - return Some(FPDecimal::FIVE); - } - if exponent == FPDecimal::TWO { - return Some(FPDecimal::from(25u128)); - } - if exponent == FPDecimal::THREE { - return Some(FPDecimal::from(125u128)); - } - if exponent == FPDecimal::FOUR { - return Some(FPDecimal::from(625u128)); - } - if exponent == FPDecimal::FIVE { - return Some(FPDecimal::from(3125u128)); - } - if exponent == FPDecimal::SIX { - return Some(FPDecimal::from(15625u128)); - } - if exponent == FPDecimal::SEVEN { - return Some(FPDecimal::from(78125u128)); - } - if exponent == FPDecimal::EIGHT { - return Some(FPDecimal::from(390625u128)); - } - if exponent == FPDecimal::NINE { - return Some(FPDecimal::from(1953125u128)); - } - if exponent == FPDecimal::TEN { - return Some(FPDecimal::from(9765625u128)); - } - if exponent == FPDecimal::ELEVEN { - return Some(FPDecimal::from(48828125u128)); - } - if exponent == FPDecimal::from(12u128) { - return Some(FPDecimal::from(244140625u128)); - } - if exponent == FPDecimal::from(13u128) { - return Some(FPDecimal::from(1220703125u128)); - } - if exponent == FPDecimal::from(14u128) { - return Some(FPDecimal::from(6103515625u128)); - } - if exponent == FPDecimal::from(15u128) { - return Some(FPDecimal::from(30517578125u128)); - } - } - - if base == FPDecimal::SEVEN { - if exponent == FPDecimal::ONE { - return Some(FPDecimal::SEVEN); - } - if exponent == FPDecimal::TWO { - return Some(FPDecimal::from(49u128)); - } - if exponent == FPDecimal::THREE { - return Some(FPDecimal::from(343u128)); - } - if exponent == FPDecimal::FOUR { - return Some(FPDecimal::from(2401u128)); - } - if exponent == FPDecimal::FIVE { - return Some(FPDecimal::from(16807u128)); - } - if exponent == FPDecimal::SIX { - return Some(FPDecimal::from(117649u128)); - } - if exponent == FPDecimal::SEVEN { - return Some(FPDecimal::from(823543u128)); - } - if exponent == FPDecimal::EIGHT { - return Some(FPDecimal::from(5764801u128)); - } - if exponent == FPDecimal::NINE { - return Some(FPDecimal::from(40353607u128)); - } - if exponent == FPDecimal::TEN { - return Some(FPDecimal::from(282475249u128)); - } - if exponent == FPDecimal::ELEVEN { - return Some(FPDecimal::from(1977326743u128)); - } - if exponent == FPDecimal::from(12u128) { - return Some(FPDecimal::from(13841287201u128)); - } - if exponent == FPDecimal::from(13u128) { - return Some(FPDecimal::from(96889010407u128)); - } - if exponent == FPDecimal::from(14u128) { - return Some(FPDecimal::from(678223072849u128)); - } - if exponent == FPDecimal::from(15u128) { - return Some(FPDecimal::from(4747561509943u128)); - } - } - - if base == FPDecimal::from(10u128) { - if exponent == FPDecimal::ONE { - return Some(FPDecimal::from(10u128)); - } - if exponent == FPDecimal::TWO { - return Some(FPDecimal::from(100u128)); - } - if exponent == FPDecimal::THREE { - return Some(FPDecimal::from(1000u128)); - } - if exponent == FPDecimal::FOUR { - return Some(FPDecimal::from(10000u128)); - } - if exponent == FPDecimal::FIVE { - return Some(FPDecimal::from(100000u128)); - } - if exponent == FPDecimal::SIX { - return Some(FPDecimal::from(1000000u128)); - } - if exponent == FPDecimal::SEVEN { - return Some(FPDecimal::from(10000000u128)); - } - if exponent == FPDecimal::EIGHT { - return Some(FPDecimal::from(100000000u128)); - } - if exponent == FPDecimal::NINE { - return Some(FPDecimal::from(1000000000u128)); - } - if exponent == FPDecimal::TEN { - return Some(FPDecimal::from(10000000000u128)); - } - if exponent == FPDecimal::ELEVEN { - return Some(FPDecimal::from(100000000000u128)); - } - if exponent == FPDecimal::from(12u128) { - return Some(FPDecimal::from(1000000000000u128)); - } - if exponent == FPDecimal::from(13u128) { - return Some(FPDecimal::from(10000000000000u128)); - } - if exponent == FPDecimal::from(14u128) { - return Some(FPDecimal::from(100000000000000u128)); - } - if exponent == FPDecimal::from(15u128) { - return Some(FPDecimal::from(1000000000000000u128)); - } - if exponent == FPDecimal::from(16u128) { - return Some(FPDecimal::from(10000000000000000u128)); - } - if exponent == FPDecimal::from(17u128) { - return Some(FPDecimal::from(100000000000000000u128)); - } - if exponent == FPDecimal::from(18u128) { - return Some(FPDecimal::from(1000000000000000000u128)); - } - if exponent == FPDecimal::from(19u128) { - return Some(FPDecimal::from(10000000000000000000u128)); - } - if exponent == FPDecimal::from(20u128) { - return Some(FPDecimal::from(100000000000000000000u128)); - } - if exponent == FPDecimal::NEGATIVE_ONE { - return Some(FPDecimal::from_str("0.1").unwrap()); - } - if exponent == FPDecimal::from_str("-2").unwrap() { - return Some(FPDecimal::from_str("0.01").unwrap()); - } - if exponent == FPDecimal::from_str("-3").unwrap() { - return Some(FPDecimal::from_str("0.001").unwrap()); - } - if exponent == FPDecimal::from_str("-4").unwrap() { - return Some(FPDecimal::from_str("0.0001").unwrap()); - } - if exponent == FPDecimal::from_str("-5").unwrap() { - return Some(FPDecimal::from_str("0.00001").unwrap()); - } - if exponent == FPDecimal::from_str("-6").unwrap() { - return Some(FPDecimal::from_str("0.000001").unwrap()); - } - if exponent == FPDecimal::from_str("-7").unwrap() { - return Some(FPDecimal::from_str("0.0000001").unwrap()); - } - if exponent == FPDecimal::from_str("-8").unwrap() { - return Some(FPDecimal::from_str("0.00000001").unwrap()); - } - if exponent == FPDecimal::from_str("-9").unwrap() { - return Some(FPDecimal::from_str("0.000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-10").unwrap() { - return Some(FPDecimal::from_str("0.0000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-11").unwrap() { - return Some(FPDecimal::from_str("0.00000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-12").unwrap() { - return Some(FPDecimal::from_str("0.000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-13").unwrap() { - return Some(FPDecimal::from_str("0.0000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-14").unwrap() { - return Some(FPDecimal::from_str("0.00000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-15").unwrap() { - return Some(FPDecimal::from_str("0.000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-16").unwrap() { - return Some(FPDecimal::from_str("0.0000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-17").unwrap() { - return Some(FPDecimal::from_str("0.00000000000000001").unwrap()); - } - if exponent == FPDecimal::from_str("-18").unwrap() { - return Some(FPDecimal::from_str("0.000000000000000001").unwrap()); - } - if exponent < FPDecimal::from_str("-18").unwrap() { - return Some(FPDecimal::ZERO); - } - if exponent == FPDecimal::from(21u128) { - return Some(FPDecimal::from(1000000000000000000000u128)); - } - if exponent == FPDecimal::from(22u128) { - return Some(FPDecimal::from(10000000000000000000000u128)); - } - if exponent == FPDecimal::from(23u128) { - return Some(FPDecimal::from(100000000000000000000000u128)); - } - if exponent == FPDecimal::from(24u128) { - return Some(FPDecimal::from(1000000000000000000000000u128)); - } - if exponent == FPDecimal::from(25u128) { - return Some(FPDecimal::from(10000000000000000000000000u128)); - } - if exponent == FPDecimal::from(26u128) { - return Some(FPDecimal::from(100000000000000000000000000u128)); - } - if exponent == FPDecimal::from(27u128) { - return Some(FPDecimal::from(1000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(28u128) { - return Some(FPDecimal::from(10000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(29u128) { - return Some(FPDecimal::from(100000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(30u128) { - return Some(FPDecimal::from(1000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(31u128) { - return Some(FPDecimal::from(10000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(32u128) { - return Some(FPDecimal::from(100000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(33u128) { - return Some(FPDecimal::from(1000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(34u128) { - return Some(FPDecimal::from(10000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(35u128) { - return Some(FPDecimal::from(100000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(36u128) { - return Some(FPDecimal::from(1000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(37u128) { - return Some(FPDecimal::from(10000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(38u128) { - return Some(FPDecimal::from(100000000000000000000000000000000000000u128)); - } - if exponent == FPDecimal::from(39u128) { - return Some(FPDecimal::from_str("1000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(40u128) { - return Some(FPDecimal::from_str("10000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(41u128) { - return Some(FPDecimal::from_str("100000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(42u128) { - return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(43u128) { - return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(44u128) { - return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(45u128) { - return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(46u128) { - return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(47u128) { - return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(48u128) { - return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(49u128) { - return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(50u128) { - return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(51u128) { - return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(52u128) { - return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(53u128) { - return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(54u128) { - return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(55u128) { - return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(56u128) { - return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(57u128) { - return Some(FPDecimal::from_str("1000000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(58u128) { - return Some(FPDecimal::from_str("10000000000000000000000000000000000000000000000000000000000").unwrap()); - } - if exponent == FPDecimal::from(59u128) { - return Some(FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000000").unwrap()); - } - } - - if base == FPDecimal::ELEVEN { - if exponent == FPDecimal::ONE { - return Some(FPDecimal::ELEVEN); - } - if exponent == FPDecimal::TWO { - return Some(FPDecimal::from(121u128)); - } - if exponent == FPDecimal::THREE { - return Some(FPDecimal::from(1331u128)); - } - if exponent == FPDecimal::FOUR { - return Some(FPDecimal::from(14641u128)); - } - if exponent == FPDecimal::FIVE { - return Some(FPDecimal::from(161051u128)); - } - if exponent == FPDecimal::SIX { - return Some(FPDecimal::from(1771561u128)); - } - if exponent == FPDecimal::SEVEN { - return Some(FPDecimal::from(19487171u128)); - } - if exponent == FPDecimal::EIGHT { - return Some(FPDecimal::from(214358881u128)); - } - if exponent == FPDecimal::NINE { - return Some(FPDecimal::from(2357947691u128)); - } - if exponent == FPDecimal::TEN { - return Some(FPDecimal::from(25937424601u128)); - } - if exponent == FPDecimal::ELEVEN { - return Some(FPDecimal::from(285311670611u128)); - } - if exponent == FPDecimal::from(12u128) { - return Some(FPDecimal::from(3138428376721u128)); - } - if exponent == FPDecimal::from(13u128) { - return Some(FPDecimal::from(34522712143931u128)); - } - if exponent == FPDecimal::from(14u128) { - return Some(FPDecimal::from(379749833583241u128)); - } - if exponent == FPDecimal::from(15u128) { - return Some(FPDecimal::from(4177248169415651u128)); + let basic_check: [(&dyn Fn(FPDecimal) -> Option, FPDecimal); 7] = [ + (&FPDecimal::two_pow, FPDecimal::TWO), + (&FPDecimal::e_pow, FPDecimal::E), + (&FPDecimal::three_pow, FPDecimal::THREE), + (&FPDecimal::five_pow, FPDecimal::FIVE), + (&FPDecimal::seven_pow, FPDecimal::SEVEN), + (&FPDecimal::ten_pow, FPDecimal::TEN), + (&FPDecimal::eleven_pow, FPDecimal::ELEVEN), + ]; + + for (exp_fn, basic_case) in basic_check { + if base == basic_case { + return exp_fn(exponent); } } None diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 7bdc6c79..0b6f0d8d 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -114,6 +114,18 @@ impl FPDecimal { if self == FPDecimal::from(2048u128) { return Some(FPDecimal::ELEVEN); } + if self == FPDecimal::from(4096u128) { + return Some(FPDecimal::from(12u128)); + } + if self == FPDecimal::from(8192u128) { + return Some(FPDecimal::from(13u128)); + } + if self == FPDecimal::from(16384u128) { + return Some(FPDecimal::from(14u128)); + } + if self == FPDecimal::from(32768u128) { + return Some(FPDecimal::from(15u128)); + } if self == FPDecimal::ONE / FPDecimal::TWO { return Some(-FPDecimal::ONE); @@ -148,6 +160,18 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(2048u128) { return Some(-FPDecimal::ELEVEN); } + if self == FPDecimal::ONE / FPDecimal::from(4096u128) { + return Some(-FPDecimal::from(12u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(8192u128) { + return Some(-FPDecimal::from(13u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(16384u128) { + return Some(-FPDecimal::from(14u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(32768u128) { + return Some(-FPDecimal::from(15u128)); + } None } @@ -188,6 +212,18 @@ impl FPDecimal { if self == FPDecimal::from(177147u128) { return Some(FPDecimal::ELEVEN); } + if self == FPDecimal::from(531441u128) { + return Some(FPDecimal::from(12u128)); + } + if self == FPDecimal::from(531441u128) { + return Some(FPDecimal::from(13u128)); + } + if self == FPDecimal::from(4782969u128) { + return Some(FPDecimal::from(14u128)); + } + if self == FPDecimal::from(14348907u128) { + return Some(FPDecimal::from(15u128)); + } if self == FPDecimal::ONE / FPDecimal::THREE { return Some(-FPDecimal::ONE); @@ -222,6 +258,18 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(177147u128) { return Some(-FPDecimal::ELEVEN); } + if self == FPDecimal::ONE / FPDecimal::from(531441u128) { + return Some(-FPDecimal::from(12u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(531441u128) { + return Some(-FPDecimal::from(13u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(4782969u128) { + return Some(-FPDecimal::from(14u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(14348907u128) { + return Some(-FPDecimal::from(15u128)); + } None } @@ -263,6 +311,18 @@ impl FPDecimal { if self == FPDecimal::from(48828125u128) { return Some(FPDecimal::ELEVEN); } + if self == FPDecimal::from(244140625u128) { + return Some(FPDecimal::from(12u128)); + } + if self == FPDecimal::from(1220703125u128) { + return Some(FPDecimal::from(13u128)); + } + if self == FPDecimal::from(6103515625u128) { + return Some(FPDecimal::from(14u128)); + } + if self == FPDecimal::from(30517578125u128) { + return Some(FPDecimal::from(15u128)); + } if self == FPDecimal::ONE / FPDecimal::FIVE { return Some(-FPDecimal::ONE); @@ -297,6 +357,18 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(48828125u128) { return Some(-FPDecimal::ELEVEN); } + if self == FPDecimal::ONE / FPDecimal::from(244140625u128) { + return Some(-FPDecimal::from(12u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(1220703125u128) { + return Some(-FPDecimal::from(13u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(6103515625u128) { + return Some(-FPDecimal::from(14u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(30517578125u128) { + return Some(-FPDecimal::from(15u128)); + } None } @@ -339,6 +411,19 @@ impl FPDecimal { if self == FPDecimal::from(1977326743u128) { return Some(FPDecimal::ELEVEN); } + if self == FPDecimal::from(13841287201u128) { + return Some(FPDecimal::from(12u128)); + } + if self == FPDecimal::from(96889010407u128) { + return Some(FPDecimal::from(13u128)); + } + if self == FPDecimal::from(678223072849u128) { + return Some(FPDecimal::from(14u128)); + } + if self == FPDecimal::from(4747561509943u128) { + return Some(FPDecimal::from(15u128)); + } + if self == FPDecimal::ONE / FPDecimal::SEVEN { return Some(-FPDecimal::ONE); } @@ -372,6 +457,18 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(1977326743u128) { return Some(-FPDecimal::ELEVEN); } + if self == FPDecimal::ONE / FPDecimal::from(13841287201u128) { + return Some(-FPDecimal::from(12u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(96889010407u128) { + return Some(-FPDecimal::from(13u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(678223072849u128) { + return Some(-FPDecimal::from(14u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(4747561509943u128) { + return Some(-FPDecimal::from(15u128)); + } None } @@ -413,6 +510,18 @@ impl FPDecimal { if self == FPDecimal::from(100_000_000_000u128) { return Some(FPDecimal::ELEVEN); } + if self == FPDecimal::from(1_000_000_000_000u128) { + return Some(FPDecimal::from(12u128)); + } + if self == FPDecimal::from(10_000_000_000_000u128) { + return Some(FPDecimal::from(13u128)); + } + if self == FPDecimal::from(100_000_000_000_000u128) { + return Some(FPDecimal::from(14u128)); + } + if self == FPDecimal::from(1_000_000_000_000_000u128) { + return Some(FPDecimal::from(15u128)); + } if self == FPDecimal::ONE / FPDecimal::TEN { return Some(-FPDecimal::ONE); @@ -447,6 +556,19 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(100_000_000_000u128) { return Some(-FPDecimal::ELEVEN); } + if self == FPDecimal::ONE / FPDecimal::from(1_000_000_000_000u128) { + return Some(-FPDecimal::from(12u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(10_000_000_000_000u128) { + return Some(-FPDecimal::from(13u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(100_000_000_000_000u128) { + return Some(-FPDecimal::from(14u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(1_000_000_000_000_000u128) { + return Some(-FPDecimal::from(15u128)); + } + None } @@ -488,6 +610,18 @@ impl FPDecimal { if self == FPDecimal::from(285311670611u128) { return Some(FPDecimal::ELEVEN); } + if self == FPDecimal::from(3138428376721u128) { + return Some(FPDecimal::from(12u128)); + } + if self == FPDecimal::from(34522712143931u128) { + return Some(FPDecimal::from(13u128)); + } + if self == FPDecimal::from(379749833583241u128) { + return Some(FPDecimal::from(14u128)); + } + if self == FPDecimal::from(4177248169415651u128) { + return Some(FPDecimal::from(15u128)); + } if self == FPDecimal::ONE / FPDecimal::ELEVEN { return Some(-FPDecimal::ONE); @@ -522,6 +656,18 @@ impl FPDecimal { if self == FPDecimal::ONE / FPDecimal::from(285311670611u128) { return Some(-FPDecimal::ELEVEN); } + if self == FPDecimal::ONE / FPDecimal::from(3138428376721u128) { + return Some(-FPDecimal::from(12u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(34522712143931u128) { + return Some(-FPDecimal::from(13u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(379749833583241u128) { + return Some(-FPDecimal::from(14u128)); + } + if self == FPDecimal::ONE / FPDecimal::from(4177248169415651u128) { + return Some(-FPDecimal::from(15u128)); + } None } From 70d56ee061453c7d05435a30a4fc7ef7d3f11e6e Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Fri, 27 Oct 2023 11:38:38 -0400 Subject: [PATCH 22/26] fixed lint --- packages/injective-math/src/fp_decimal/exp.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 581523fe..eea49614 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -1055,8 +1055,10 @@ impl FPDecimal { if base == FPDecimal::ONE { return Some(FPDecimal::ONE); } + // type + type BaseFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); - let basic_check: [(&dyn Fn(FPDecimal) -> Option, FPDecimal); 7] = [ + let basic_check: [BaseFunction; 7] = [ (&FPDecimal::two_pow, FPDecimal::TWO), (&FPDecimal::e_pow, FPDecimal::E), (&FPDecimal::three_pow, FPDecimal::THREE), From e123c1f68b103ea6754efb5f721339c6246fe758 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Fri, 27 Oct 2023 11:50:01 -0400 Subject: [PATCH 23/26] minor improvements --- packages/injective-math/src/fp_decimal/exp.rs | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index eea49614..6bece868 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -232,6 +232,95 @@ impl FPDecimal { return Some(FPDecimal::ONE / FPDecimal::from(32768u128)); } + if FPDecimal::ONE.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE); + } + if FPDecimal::TWO.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::TWO); + } + if FPDecimal::THREE.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::THREE); + } + if FPDecimal::FOUR.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::FOUR); + } + if FPDecimal::FIVE.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::FIVE); + } + if FPDecimal::SIX.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::SIX); + } + if FPDecimal::SEVEN.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::SEVEN); + } + if FPDecimal::EIGHT.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::EIGHT); + } + if FPDecimal::NINE.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::NINE); + } + if FPDecimal::TEN.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::TEN); + } + if FPDecimal::ELEVEN.log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::ELEVEN); + } + if FPDecimal::from(12u128).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::from(12u128)); + } + if FPDecimal::from(13u128).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::from(13u128)); + } + if FPDecimal::from(14u128).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::from(14u128)); + } + if FPDecimal::from(15u128).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ONE / FPDecimal::from(15u128)); + } + + if (FPDecimal::ONE / FPDecimal::TWO).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::TWO); + } + if (FPDecimal::ONE / FPDecimal::THREE).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::THREE); + } + if (FPDecimal::ONE / FPDecimal::FOUR).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::FOUR); + } + if (FPDecimal::ONE / FPDecimal::FIVE).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::FIVE); + } + if (FPDecimal::ONE / FPDecimal::SIX).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::SIX); + } + if (FPDecimal::ONE / FPDecimal::SEVEN).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::SEVEN); + } + if (FPDecimal::ONE / FPDecimal::EIGHT).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::EIGHT); + } + if (FPDecimal::ONE / FPDecimal::NINE).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::NINE); + } + if (FPDecimal::ONE / FPDecimal::TEN).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::TEN); + } + if (FPDecimal::ONE / FPDecimal::ELEVEN).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::ELEVEN); + } + if (FPDecimal::ONE / FPDecimal::from(12u128)).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::from(12u128)); + } + if (FPDecimal::ONE / FPDecimal::from(13u128)).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::from(13u128)); + } + if (FPDecimal::ONE / FPDecimal::from(14u128)).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::from(14u128)); + } + if (FPDecimal::ONE / FPDecimal::from(15u128)).log2().is_some_and(|x| x == -exponent) { + return Some(FPDecimal::from(15u128)); + } + None } From 04b4e6e658e376edba9895d17cea7c50eff59bb0 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Mon, 30 Oct 2023 12:12:05 -0400 Subject: [PATCH 24/26] add more unit tests --- packages/injective-math/src/fp_decimal/exp.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 6bece868..37918655 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -1904,7 +1904,26 @@ mod tests { } // NOTE: its ok we ignore these two unit tests. they should not be the goal of this crate + // TODO: add a lookup table for this in future /* + #[test] + fn test_ln_e_pow_1_5() { + let base = FPDecimal::E * FPDecimal::E.sqrt(); + assert_eq!(base.ln(), FPDecimal::must_from_str("1.5")); + } + + #[test] + fn test_ln_e_pow_minus_1_5() { + let base = FPDecimal::ONE / (FPDecimal::E.sqrt() * FPDecimal::E); + assert_eq!(base.ln(), FPDecimal::must_from_str("-1.5")); + } + #[test] + fn test_log_1_5_2_2_5() { + let base = FPDecimal::must_from_str("1.5"); + let exp = FPDecimal::must_from_str("2.25"); + assert_eq!(exp.log(base), FPDecimal::TWO); + } + #[test] fn test_25_pow_0_11111() { let power = FPDecimal::ONE / FPDecimal::from(9_u128); From bc6114301a59a9a35c066196375fd13b062af6d1 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Mon, 30 Oct 2023 17:40:37 -0400 Subject: [PATCH 25/26] add more constants --- packages/injective-math/src/fp_decimal/mod.rs | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/packages/injective-math/src/fp_decimal/mod.rs b/packages/injective-math/src/fp_decimal/mod.rs index 750f8e90..5b9d373b 100644 --- a/packages/injective-math/src/fp_decimal/mod.rs +++ b/packages/injective-math/src/fp_decimal/mod.rs @@ -219,16 +219,113 @@ impl FPDecimal { sign: 1, }; // ln(1.5) + pub const LN_2: FPDecimal = FPDecimal { + // 405_465_108_704_634_977 + num: U256([693_147_180_559_945_309, 0, 0, 0]), + sign: 1, + }; // ln(1.5) + pub const LN_10: FPDecimal = FPDecimal { num: U256([2_302_585_092_994_045_684, 0, 0, 0]), sign: 1, }; // ln(10) + pub const LOG2_10: FPDecimal = FPDecimal { + // 3.321_928_094_887_362_347 + num: U256([3_321_928_094_887_362_347, 0, 0, 0]), + sign: 1, + }; // log2(10) + + pub const LOG2_E: FPDecimal = FPDecimal { + // 1.4426950408889633306 + num: U256([1_442_695_040_888_963_330, 0, 0, 0]), + sign: 1, + }; // log2(10) + + pub const LOG10_2: FPDecimal = FPDecimal { + // 0.30102999566398119523 + num: U256([301_029_995_663_981_195, 0, 0, 0]), + sign: 1, + }; + + pub const LOG10_E: FPDecimal = FPDecimal { + // 0.30102999566398119523 + num: U256([301_029_995_663_981_195, 0, 0, 0]), + sign: 1, + }; + pub const PI: FPDecimal = FPDecimal { num: U256([3_141_592_653_589_793_115, 0, 0, 0]), sign: 1, }; + pub const FRAC_1_PI: FPDecimal = FPDecimal { + // 318_309_886_183_790_683 + num: U256([318_309_886_183_790_683, 0, 0, 0]), + sign: 1, + }; + + pub const FRAC_1_SQRT_2: FPDecimal = FPDecimal { + // 0.707106781186547524 + num: U256([707_106_781_186_547_524, 0, 0, 0]), + sign: 1, + }; + + pub const FRAC_2_PI: FPDecimal = FPDecimal { + // 636_619_772_367_581_3679 + num: U256([636_619_772_367_581_368, 0, 0, 0]), + sign: 1, + }; + + pub const FRAC_2_SQRT_PI: FPDecimal = FPDecimal { + // 1_128_379_167_095_512_595 + num: U256([1_128_379_167_095_512_595, 0, 0, 0]), + sign: 1, + }; + + pub const FRAC_PI_2: FPDecimal = FPDecimal { + // 1_570_796_326_794_896_558 + num: U256([1_570_796_326_794_896_558, 0, 0, 0]), + sign: 1, + }; + + pub const FRAC_PI_3: FPDecimal = FPDecimal { + // 1_047_197_551_196_597_705 + num: U256([1_047_197_551_196_597_705, 0, 0, 0]), + sign: 1, + }; + + pub const FRAC_PI_4: FPDecimal = FPDecimal { + // 0_785_398_163_397_448_279 + num: U256([785_398_163_397_448_279, 0, 0, 0]), + sign: 1, + }; + + pub const FRAC_PI_6: FPDecimal = FPDecimal { + // 523_598_775_598_298_852 + num: U256([523_598_775_598_298_852, 0, 0, 0]), + sign: 1, + }; + + pub const FRAC_PI_8: FPDecimal = FPDecimal { + // 392_699_081_698_724_139 + num: U256([392_699_081_698_724_139, 0, 0, 0]), + sign: 1, + }; + + pub const SQRT_2: FPDecimal = FPDecimal { + // 1.414_213_562_373_095_048 + num: U256([1_414_213_562_373_095_048, 0, 0, 0]), + sign: 1, + }; + + pub const TAU: FPDecimal = FPDecimal { + // 2*PI + // 6.283185307179586232 + num: U256([6_283_185_307_179_586_232, 0, 0, 0]), + sign: 1, + }; + pub fn is_zero(&self) -> bool { self.num.is_zero() } From 8d6104f341fab585d5eb0bbda4cbe1a8a85c6a0b Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Tue, 31 Oct 2023 13:08:08 -0400 Subject: [PATCH 26/26] log, power return FPDecimalError now --- .../src/fp_decimal/arithmetic.rs | 2 +- .../injective-math/src/fp_decimal/error.rs | 5 + packages/injective-math/src/fp_decimal/exp.rs | 258 ++++++++++-------- packages/injective-math/src/fp_decimal/log.rs | 33 ++- packages/injective-math/src/fp_decimal/mod.rs | 1 + .../injective-math/src/fp_decimal/scale.rs | 2 +- .../src/fp_decimal/trigonometry.rs | 10 +- packages/injective-math/src/root_findings.rs | 4 +- 8 files changed, 176 insertions(+), 139 deletions(-) create mode 100644 packages/injective-math/src/fp_decimal/error.rs diff --git a/packages/injective-math/src/fp_decimal/arithmetic.rs b/packages/injective-math/src/fp_decimal/arithmetic.rs index 28acd585..9c136a52 100644 --- a/packages/injective-math/src/fp_decimal/arithmetic.rs +++ b/packages/injective-math/src/fp_decimal/arithmetic.rs @@ -87,7 +87,7 @@ impl FPDecimal { } FPDecimal { - num: U256::try_from(num).unwrap(), + num: U256::try_from(num).unwrap(), // panic only in MIN_FPDeciaml/-1 sign: 1 ^ x.sign ^ y.sign, } } diff --git a/packages/injective-math/src/fp_decimal/error.rs b/packages/injective-math/src/fp_decimal/error.rs new file mode 100644 index 00000000..76d1d218 --- /dev/null +++ b/packages/injective-math/src/fp_decimal/error.rs @@ -0,0 +1,5 @@ +#[derive(Debug, PartialEq, Eq)] +pub enum FPDecimalError { + Undefined(String), + NotSupported(String), +} diff --git a/packages/injective-math/src/fp_decimal/exp.rs b/packages/injective-math/src/fp_decimal/exp.rs index 37918655..ce62bf05 100644 --- a/packages/injective-math/src/fp_decimal/exp.rs +++ b/packages/injective-math/src/fp_decimal/exp.rs @@ -1,5 +1,7 @@ +use std::cmp::Ordering; use std::str::FromStr; +use crate::fp_decimal::error::FPDecimalError; /// Exponential functions for FPDecimal use crate::fp_decimal::{FPDecimal, U256}; @@ -1129,12 +1131,16 @@ impl FPDecimal { None } - pub fn pow(self, exponent: FPDecimal) -> FPDecimal { + pub fn pow(self, exponent: FPDecimal) -> Result { if self.is_zero() { - return self; + match exponent.cmp(&FPDecimal::ZERO) { + Ordering::Greater => return Ok(self), + Ordering::Equal => return Ok(FPDecimal::ONE), + Ordering::Less => return Err(FPDecimalError::NotSupported("Not supported".to_owned())), + } } if self > FPDecimal::ZERO && exponent == FPDecimal::ZERO { - return FPDecimal::ONE; + return Ok(FPDecimal::ONE); } // NOTE: x^(1/3) won't be precise if exponent == FPDecimal::ONE / FPDecimal::TWO { @@ -1169,23 +1175,23 @@ impl FPDecimal { if exponent.is_int() { if exponent % FPDecimal::TWO == FPDecimal::ONE { if let Some(value) = common_const_checks(-self, exponent) { - return -value; + return Ok(-value); } } else if exponent % FPDecimal::TWO == FPDecimal::ZERO { if let Some(value) = common_const_checks(-self, exponent) { - return value; + return Ok(value); } } - return FPDecimal::exp(exponent * (-self).ln()); + return Ok(FPDecimal::exp(exponent * (-self).ln())); } else { - panic!("No complex numer"); + return Err(FPDecimalError::NotSupported("No complex number".to_owned())); } } if exponent.abs() == FPDecimal::ONE / FPDecimal::TWO { if exponent > FPDecimal::ZERO { return self.sqrt(); } else { - return FPDecimal::ONE / self.sqrt(); + return Ok(FPDecimal::ONE / self.sqrt().unwrap()); } } @@ -1214,11 +1220,11 @@ impl FPDecimal { type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option, FPDecimal); if let Some(value) = common_const_checks(self, exponent) { - return value; + return Ok(value); } match common_checks(exponent) { - Some(value) => value, + Some(value) => Ok(value), None => { let base_checks: Vec = vec![ (&FPDecimal::log_e, FPDecimal::E), @@ -1232,16 +1238,16 @@ impl FPDecimal { for (log_fn, divisor) in base_checks { if let Some(value) = log_fn(exponent) { if self == divisor { - return value; + return Ok(value); } } if let Some(value) = log_fn(self) { if FPDecimal::ONE / value == exponent { - return divisor; + return Ok(divisor); } } } - FPDecimal::exp(exponent * self.ln()) + Ok(FPDecimal::exp(exponent * self.ln())) } } } @@ -1286,42 +1292,44 @@ impl FPDecimal { val } - fn _sqrt(a: FPDecimal) -> Option { + pub fn sqrt(self) -> Result { const MAX_ITERATIONS: i64 = 300; - if a < FPDecimal::ZERO { - return None; + if self < FPDecimal::ZERO { + return Err(FPDecimalError::NotSupported("No complex number".to_owned())); + // return None; } - if a.is_zero() { - return Some(FPDecimal::ZERO); + if self.is_zero() { + return Ok(FPDecimal::ZERO); } // Start with an arbitrary number as the first guess - let mut r = a / FPDecimal::TWO; + let mut r = self / FPDecimal::TWO; let mut l = r + FPDecimal::ONE; // Keep going while the difference is larger than the tolerance let mut c = 0i64; while (l != r) && (c < MAX_ITERATIONS) { l = r; - r = (r + a / r) / FPDecimal::TWO; + r = (r + self / r) / FPDecimal::TWO; c += 1; } - Some(r) - } - pub fn sqrt(self) -> FPDecimal { - match FPDecimal::_sqrt(self) { - Some(value) => value, - None => panic!("Undefined behavior"), - } + Ok(r) } + // pub fn sqrt(self) -> FPDecimal { + // match FPDecimal::_sqrt(self) { + // Some(value) => value, + // None => panic!("Undefined behavior"), + // } + // } } #[cfg(test)] mod tests { + use crate::fp_decimal::error::FPDecimalError; use crate::fp_decimal::U256; use crate::FPDecimal; use std::str::FromStr; @@ -1471,22 +1479,28 @@ mod tests { fn test_exp10() { assert_eq!(FPDecimal::exp(FPDecimal::TEN), FPDecimal::E_10); } + #[test] + fn test_pow_neg() { + assert_eq!( + FPDecimal::pow(FPDecimal::ZERO, -FPDecimal::ONE.div(2i128)).unwrap_err(), + FPDecimalError::NotSupported("Not supported".to_owned()) + ); + } #[test] fn test_pow_zero() { - FPDecimal::pow(FPDecimal::ZERO, FPDecimal::ONE.div(2i128)); - assert_eq!(FPDecimal::ZERO.pow(FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(FPDecimal::ZERO.pow(FPDecimal::ONE).unwrap(), FPDecimal::ZERO); } #[test] fn test_4_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::FOUR, FPDecimal::must_from_str("0.5")), FPDecimal::TWO); + assert_eq!(FPDecimal::pow(FPDecimal::FOUR, FPDecimal::must_from_str("0.5")).unwrap(), FPDecimal::TWO); } #[test] fn test_128_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(128u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(128u128), FPDecimal::must_from_str("0.5")).unwrap(), FPDecimal::must_from_str("11.313708498984760390") ); } @@ -1494,27 +1508,30 @@ mod tests { #[test] fn test_128_pow_1_7() { assert_eq!( - FPDecimal::pow(FPDecimal::from(128u128), FPDecimal::ONE / FPDecimal::SEVEN), + FPDecimal::pow(FPDecimal::from(128u128), FPDecimal::ONE / FPDecimal::SEVEN).unwrap(), FPDecimal::TWO ); } #[test] fn test_9_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::NINE, FPDecimal::must_from_str("0.5")), FPDecimal::THREE); + assert_eq!( + FPDecimal::pow(FPDecimal::NINE, FPDecimal::must_from_str("0.5")).unwrap(), + FPDecimal::THREE + ); } #[test] fn test_27_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(27u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(27u128), FPDecimal::must_from_str("0.5")).unwrap(), FPDecimal::must_from_str("5.196152422706631880") ); } #[test] fn test_27_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(27u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(27u128), FPDecimal::ONE / FPDecimal::THREE).unwrap(), FPDecimal::THREE ); } @@ -1522,32 +1539,38 @@ mod tests { #[test] fn test_81_pow_0_25() { assert_eq!( - FPDecimal::pow(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::FOUR).unwrap(), FPDecimal::THREE ); } #[test] fn test_81_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::TWO), FPDecimal::NINE); + assert_eq!( + FPDecimal::pow(FPDecimal::from(81u128), FPDecimal::ONE / FPDecimal::TWO).unwrap(), + FPDecimal::NINE + ); } #[test] fn test_25_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::from(25u128), FPDecimal::must_from_str("0.5")), FPDecimal::FIVE); + assert_eq!( + FPDecimal::pow(FPDecimal::from(25u128), FPDecimal::must_from_str("0.5")).unwrap(), + FPDecimal::FIVE + ); } #[test] fn test_125_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(125u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(125u128), FPDecimal::must_from_str("0.5")).unwrap(), FPDecimal::must_from_str("11.180339887498948482") ); } #[test] fn test_125_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(125u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(125u128), FPDecimal::ONE / FPDecimal::THREE).unwrap(), FPDecimal::FIVE ); } @@ -1555,27 +1578,30 @@ mod tests { #[test] fn test_625_pow_0_25() { assert_eq!( - FPDecimal::pow(FPDecimal::from(625u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::from(625u128), FPDecimal::ONE / FPDecimal::FOUR).unwrap(), FPDecimal::FIVE ); } #[test] fn test_49_pow_0_5() { - assert_eq!(FPDecimal::pow(FPDecimal::from(49u128), FPDecimal::must_from_str("0.5")), FPDecimal::SEVEN); + assert_eq!( + FPDecimal::pow(FPDecimal::from(49u128), FPDecimal::must_from_str("0.5")).unwrap(), + FPDecimal::SEVEN + ); } #[test] fn test_343_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(343u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(343u128), FPDecimal::must_from_str("0.5")).unwrap(), FPDecimal::must_from_str("18.520259177452134133") ); } #[test] fn test_343_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(343u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(343u128), FPDecimal::ONE / FPDecimal::THREE).unwrap(), FPDecimal::SEVEN ); } @@ -1583,7 +1609,7 @@ mod tests { #[test] fn test_2401_pow_0_25() { assert_eq!( - FPDecimal::pow(FPDecimal::from(2401u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::from(2401u128), FPDecimal::ONE / FPDecimal::FOUR).unwrap(), FPDecimal::SEVEN ); } @@ -1591,7 +1617,7 @@ mod tests { #[test] fn test_121_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(121u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(121u128), FPDecimal::must_from_str("0.5")).unwrap(), FPDecimal::ELEVEN ); } @@ -1599,14 +1625,14 @@ mod tests { #[test] fn test_1331_pow_0_5() { assert_eq!( - FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::must_from_str("0.5")), + FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::must_from_str("0.5")).unwrap(), FPDecimal::must_from_str("36.48287269390939834") ); } #[test] fn test_1331_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(1331u128), FPDecimal::ONE / FPDecimal::THREE).unwrap(), FPDecimal::ELEVEN ); } @@ -1614,70 +1640,72 @@ mod tests { #[test] fn test_14641_pow_0_25() { assert_eq!( - FPDecimal::pow(FPDecimal::from(14641u128), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::from(14641u128), FPDecimal::ONE / FPDecimal::FOUR).unwrap(), FPDecimal::ELEVEN ); } #[test] fn test_2_pow_1() { - assert_eq!(FPDecimal::TWO.pow(FPDecimal::ONE), FPDecimal::TWO); + assert_eq!(FPDecimal::TWO.pow(FPDecimal::ONE).unwrap(), FPDecimal::TWO); } #[test] fn test_3_pow_1() { - assert_eq!(FPDecimal::THREE.pow(FPDecimal::ONE), FPDecimal::THREE); + assert_eq!(FPDecimal::THREE.pow(FPDecimal::ONE).unwrap(), FPDecimal::THREE); } #[test] fn test_pow_exp_1() { - assert_eq!(FPDecimal::E.pow(FPDecimal::ONE), FPDecimal::E); + assert_eq!(FPDecimal::E.pow(FPDecimal::ONE).unwrap(), FPDecimal::E); } #[test] fn test_pow_exp_0() { - assert_eq!(FPDecimal::E.pow(FPDecimal::ZERO), FPDecimal::ONE); + assert_eq!(FPDecimal::E.pow(FPDecimal::ZERO).unwrap(), FPDecimal::ONE); } #[test] fn test_pow_exp_10() { assert_eq!( - FPDecimal::E.pow(FPDecimal { - num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, - sign: 1 - }), + FPDecimal::E + .pow(FPDecimal { + num: U256([10, 0, 0, 0]) * FPDecimal::ONE.num, + sign: 1 + }) + .unwrap(), FPDecimal::E_10 ); } #[test] fn test_pow_zero_2() { - FPDecimal::ZERO.pow(FPDecimal::ONE.div(2i128)); + assert_eq!(FPDecimal::ZERO.pow(FPDecimal::ONE.div(2i128)).unwrap(), FPDecimal::ZERO); } #[test] fn test_square_root() { let inputs: Vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 25, -1]; - let expected: Vec> = vec![ - Some(FPDecimal::ZERO), - Some(FPDecimal::ONE), - Some(FPDecimal::from_str("1.414213562373095048").unwrap()), - Some(FPDecimal::from_str("1.732050807568877293").unwrap()), - Some(FPDecimal::TWO), - Some(FPDecimal::from_str("2.236067977499789696").unwrap()), - Some(FPDecimal::from_str("2.449489742783178098").unwrap()), - Some(FPDecimal::from_str("2.645751311064590590").unwrap()), - Some(FPDecimal::from_str("2.828427124746190097").unwrap()), - Some(FPDecimal::THREE), - Some(FPDecimal::from_str("3.162277660168379331").unwrap()), - Some(FPDecimal::FOUR), - Some(FPDecimal::FIVE), - None, + let expected = vec![ + Ok(FPDecimal::ZERO), + Ok(FPDecimal::ONE), + Ok(FPDecimal::from_str("1.414213562373095048").unwrap()), + Ok(FPDecimal::from_str("1.732050807568877293").unwrap()), + Ok(FPDecimal::TWO), + Ok(FPDecimal::from_str("2.236067977499789696").unwrap()), + Ok(FPDecimal::from_str("2.449489742783178098").unwrap()), + Ok(FPDecimal::from_str("2.645751311064590590").unwrap()), + Ok(FPDecimal::from_str("2.828427124746190097").unwrap()), + Ok(FPDecimal::THREE), + Ok(FPDecimal::from_str("3.162277660168379331").unwrap()), + Ok(FPDecimal::FOUR), + Ok(FPDecimal::FIVE), + Err(FPDecimalError::NotSupported("No complex number".to_owned())), ]; for (ix, el) in inputs.iter().enumerate() { - let result = FPDecimal::_sqrt(FPDecimal::from(*el)); + let result = FPDecimal::from(*el).sqrt(); assert_eq!(result, expected[ix]); } @@ -1686,14 +1714,14 @@ mod tests { #[test] fn test_pow_10_positive() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow(FPDecimal::from_str("6").unwrap()), FPDecimal::from_str("1000000").unwrap()); + assert_eq!(base.pow(FPDecimal::must_from_str("6")).unwrap(), FPDecimal::must_from_str("1000000")); } #[test] fn test_pow_10_max() { let base = FPDecimal::from(10u128); assert_eq!( - base.pow(FPDecimal::from_str("59").unwrap()), + base.pow(FPDecimal::must_from_str("59")).unwrap(), FPDecimal::from_str("100000000000000000000000000000000000000000000000000000000000").unwrap() ); } @@ -1702,30 +1730,30 @@ mod tests { #[should_panic] fn test_pow_10_overflow() { let base = FPDecimal::from(10u128); - base.pow(FPDecimal::from_str("60").unwrap()); + base.pow(FPDecimal::must_from_str("60")).unwrap(); } #[test] fn test_pow_10_neg_3() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow(FPDecimal::from_str("-3").unwrap()), FPDecimal::from_str("0.001").unwrap()); + assert_eq!(base.pow(FPDecimal::must_from_str("-3")).unwrap(), FPDecimal::must_from_str("0.001")); } #[test] fn test_e_pow_neg_3() { let base = FPDecimal::E; assert_eq!( - base.pow(FPDecimal::from_str("-3").unwrap()), - FPDecimal::from_str("0.049787068367863943").unwrap() + base.pow(FPDecimal::must_from_str("-3")).unwrap(), + FPDecimal::must_from_str("0.049787068367863943") ); } #[test] fn test_e_pow_0_5() { assert_eq!( - FPDecimal::E.pow(FPDecimal::from_str("0.5").unwrap()), + FPDecimal::E.pow(FPDecimal::must_from_str("0.5")).unwrap(), // 1.6487212707001281469 - FPDecimal::from_str("1.648721270700128146").unwrap() + FPDecimal::must_from_str("1.648721270700128146") ); } @@ -1733,22 +1761,22 @@ mod tests { fn test_pow_10_min() { let base = FPDecimal::from(10u128); assert_eq!( - base.pow(FPDecimal::from_str("-18").unwrap()), - FPDecimal::from_str("0.000000000000000001").unwrap() + base.pow(FPDecimal::must_from_str("-18")).unwrap(), + FPDecimal::must_from_str("0.000000000000000001") ); } #[test] fn test_pow_10_underflow() { let base = FPDecimal::from(10u128); - assert_eq!(base.pow(FPDecimal::from_str("-19").unwrap()), FPDecimal::ZERO); + assert_eq!(base.pow(FPDecimal::must_from_str("-19")).unwrap(), FPDecimal::ZERO); } #[test] fn test_checked_2_pow_2() { let base = FPDecimal::from(2u128); - let result = FPDecimal::pow(base, FPDecimal::from(2u128)); + let result = FPDecimal::pow(base, FPDecimal::from(2u128)).unwrap(); assert_eq!(result, FPDecimal::from(4u128)); } @@ -1757,7 +1785,7 @@ mod tests { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("1.4"); // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - let result_2 = FPDecimal::pow(base, exponent); + let result_2 = FPDecimal::pow(base, exponent).unwrap(); assert_eq!(result_2, FPDecimal::must_from_str("3.209363953267971906")); } @@ -1765,7 +1793,7 @@ mod tests { fn test_2_3_pow_3_7() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("3.7"); - let result_2 = FPDecimal::pow(base, exponent); + let result_2 = FPDecimal::pow(base, exponent).unwrap(); //21.796812747431183828 assert_eq!(result_2, FPDecimal::must_from_str("21.796812747431186181")); } @@ -1775,7 +1803,7 @@ mod tests { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-1.4"); // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - let result_2 = FPDecimal::pow(base, exponent); + let result_2 = FPDecimal::pow(base, exponent).unwrap(); // 0.31158821952298012815 assert_eq!(result_2, FPDecimal::must_from_str("0.311588219522980075")); // assert_eq!(result_1, FPDecimal::must_from_str("0.311588219522980069")); @@ -1786,7 +1814,7 @@ mod tests { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-3.7"); // let result_1 = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - let result_2 = FPDecimal::pow(base, exponent); + let result_2 = FPDecimal::pow(base, exponent).unwrap(); // 0.045878267230508407006 assert_eq!(result_2, FPDecimal::must_from_str("0.045878267230508402")); // assert_eq!(result_1, FPDecimal::must_from_str("0.045878267230507924")); @@ -1796,7 +1824,7 @@ mod tests { fn test_2_3_pow_0_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("0.4"); - let result_2 = FPDecimal::pow(base, exponent); + let result_2 = FPDecimal::pow(base, exponent).unwrap(); assert_eq!(result_2, FPDecimal::must_from_str("1.395375631855639968")); } @@ -1804,7 +1832,7 @@ mod tests { fn test_2_3_pow_neg_0_4() { let base = FPDecimal::must_from_str("2.3"); let exponent = FPDecimal::must_from_str("-0.4"); - let result_2 = FPDecimal::pow(base, exponent); + let result_2 = FPDecimal::pow(base, exponent).unwrap(); // 0.71665290490285417314 assert_eq!(result_2, FPDecimal::must_from_str("0.716652904902854170")); } @@ -1814,7 +1842,7 @@ mod tests { let base = FPDecimal::ONE / FPDecimal::from(16u128); let exponent = FPDecimal::must_from_str("-0.5"); - let result = FPDecimal::pow(base, exponent); + let result = FPDecimal::pow(base, exponent).unwrap(); assert_eq!(result, FPDecimal::FOUR); } @@ -1824,14 +1852,14 @@ mod tests { let exponent = FPDecimal::must_from_str("0.5"); // let result = FPDecimal::checked_positive_pow(base, exponent).unwrap(); - let result = FPDecimal::pow(base, exponent); + let result = FPDecimal::pow(base, exponent).unwrap(); assert_eq!(result, FPDecimal::ONE / FPDecimal::FOUR); } #[test] fn test_100_pow_neg_1_over_2() { assert_eq!( - FPDecimal::pow(FPDecimal::from(100u128), FPDecimal::must_from_str("-0.5")), + FPDecimal::pow(FPDecimal::from(100u128), FPDecimal::must_from_str("-0.5")).unwrap(), FPDecimal::must_from_str("0.1") ); } @@ -1839,22 +1867,24 @@ mod tests { #[test] fn test_1000_pow_1_over_3() { assert_eq!( - FPDecimal::pow(FPDecimal::from(1000u128), FPDecimal::ONE / FPDecimal::THREE), + FPDecimal::pow(FPDecimal::from(1000u128), FPDecimal::ONE / FPDecimal::THREE).unwrap(), FPDecimal::TEN ); } #[test] - #[should_panic] fn test_neg_1000_pow_1_over_3() { - FPDecimal::pow(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::THREE); + assert_eq!( + FPDecimal::pow(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::THREE).unwrap_err(), + FPDecimalError::NotSupported("No complex number".to_owned()) + ); } #[test] fn test_neg_10_pow_3() { assert_eq!( - FPDecimal::pow(FPDecimal::must_from_str("-10"), FPDecimal::THREE), - -FPDecimal::TEN.pow(FPDecimal::THREE) + FPDecimal::pow(FPDecimal::must_from_str("-10"), FPDecimal::THREE).unwrap(), + -FPDecimal::TEN.pow(FPDecimal::THREE).unwrap() ); } @@ -1867,16 +1897,18 @@ mod tests { } #[test] - #[should_panic] fn test_neg_10_pow_2_3() { - FPDecimal::pow(FPDecimal::must_from_str("-10"), FPDecimal::must_from_str("2.3")); + assert_eq!( + FPDecimal::pow(FPDecimal::must_from_str("-10"), FPDecimal::must_from_str("2.3")).unwrap_err(), + FPDecimalError::NotSupported("No complex number".to_owned()) + ); } #[test] #[should_panic] fn test_neg_1000_pow_1_over_4() { assert_eq!( - FPDecimal::pow(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::FOUR), + FPDecimal::pow(FPDecimal::must_from_str("-1000.0"), FPDecimal::ONE / FPDecimal::FOUR).unwrap(), -FPDecimal::TEN ); } @@ -1884,23 +1916,23 @@ mod tests { #[test] fn test_exp_log_2() { // assert_eq!(FPDecimal::E.pow(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); - assert_eq!(FPDecimal::E.pow(FPDecimal::TWO.ln()), FPDecimal::must_from_str("2.0")); + assert_eq!(FPDecimal::E.pow(FPDecimal::TWO.ln()).unwrap(), FPDecimal::must_from_str("2.0")); } #[test] fn test_sqrt() { - assert_eq!(FPDecimal::FOUR.sqrt(), FPDecimal::TWO); - assert_eq!(FPDecimal::from(16u128).sqrt(), FPDecimal::FOUR); - assert_eq!(FPDecimal::ONE.sqrt(), FPDecimal::ONE); - assert_eq!(FPDecimal::NINE.sqrt(), FPDecimal::THREE); - assert_eq!(FPDecimal::from(81u128).sqrt(), FPDecimal::NINE); + assert_eq!(FPDecimal::FOUR.sqrt().unwrap(), FPDecimal::TWO); + assert_eq!(FPDecimal::from(16u128).sqrt().unwrap(), FPDecimal::FOUR); + assert_eq!(FPDecimal::ONE.sqrt().unwrap(), FPDecimal::ONE); + assert_eq!(FPDecimal::NINE.sqrt().unwrap(), FPDecimal::THREE); + assert_eq!(FPDecimal::from(81u128).sqrt().unwrap(), FPDecimal::NINE); } #[test] fn test_1_power_n() { - assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::ONE)); - assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::TWO)); - assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::THREE)); - assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::FOUR)); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::ONE).unwrap()); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::TWO).unwrap()); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::THREE).unwrap()); + assert_eq!(FPDecimal::ONE, FPDecimal::ONE.pow(FPDecimal::FOUR).unwrap()); } // NOTE: its ok we ignore these two unit tests. they should not be the goal of this crate diff --git a/packages/injective-math/src/fp_decimal/log.rs b/packages/injective-math/src/fp_decimal/log.rs index 0b6f0d8d..4d7b6189 100644 --- a/packages/injective-math/src/fp_decimal/log.rs +++ b/packages/injective-math/src/fp_decimal/log.rs @@ -1,3 +1,4 @@ +use crate::fp_decimal::error::FPDecimalError; /// Logarithmic functions for FPDecimal use crate::fp_decimal::{FPDecimal, U256}; @@ -678,26 +679,21 @@ impl FPDecimal { if a == FPDecimal::ONE { return FPDecimal::ZERO; } - if a == FPDecimal::ZERO { - // FIXME should be an undefined, not sure if it will be better to just add assert!(b>0) - panic!("Undefined"); - } a.ln() / base.ln() } - pub fn log(&self, base: FPDecimal) -> FPDecimal { + pub fn log(&self, base: FPDecimal) -> Result { assert!(base > FPDecimal::ZERO); if *self == FPDecimal::ONE { - return FPDecimal::ZERO; + return Ok(FPDecimal::ZERO); } - if *self == FPDecimal::ZERO { - // FIXME should be an undefined, not sure if it will be better to just add assert!(b>0) - return FPDecimal::SMALLEST_PRECISION; + if self.is_zero() { + return Err(FPDecimalError::Undefined("log0 ".to_owned())); } if base == FPDecimal::E { - return self.ln(); + return Ok(self.ln()); } let base_checks: Vec<&dyn Fn(FPDecimal) -> Option> = vec![ @@ -711,10 +707,10 @@ impl FPDecimal { ]; for log_fn in base_checks { if let (Some(numerator), Some(denominator)) = (log_fn(*self), log_fn(base)) { - return numerator / denominator; + return Ok(numerator / denominator); } } - FPDecimal::_log(*self, base) + Ok(FPDecimal::_log(*self, base)) } fn _two_agm(mut a0: FPDecimal, mut b0: FPDecimal, tol: FPDecimal) -> FPDecimal { @@ -723,7 +719,7 @@ impl FPDecimal { break; } let a1 = (a0 + b0) / FPDecimal::TWO; - let b1 = (a0 * b0).sqrt(); + let b1 = (a0 * b0).sqrt().unwrap(); a0 = a1; b0 = b1; } @@ -906,12 +902,15 @@ mod tests { } #[test] fn test_log_2_8() { - assert_eq!(FPDecimal::EIGHT.log(FPDecimal::TWO), FPDecimal::THREE); + assert_eq!(FPDecimal::EIGHT.log(FPDecimal::TWO).unwrap(), FPDecimal::THREE); } #[test] fn test_log_11_8() { - assert_eq!(FPDecimal::EIGHT.log(FPDecimal::ELEVEN), FPDecimal::must_from_str("0.867194478953663578")); + assert_eq!( + FPDecimal::EIGHT.log(FPDecimal::ELEVEN).unwrap(), + FPDecimal::must_from_str("0.867194478953663578") + ); } #[test] @@ -946,13 +945,13 @@ mod tests { fn test_ln4_16() { let a = FPDecimal::from(16u128); let b = FPDecimal::FOUR; - assert_eq!(a.log(b), FPDecimal::TWO); + assert_eq!(a.log(b).unwrap(), FPDecimal::TWO); } #[test] fn test_log_e_16() { let a = FPDecimal::from(16u128); let b = FPDecimal::FOUR; - assert_eq!(a.log(b), FPDecimal::TWO); + assert_eq!(a.log(b).unwrap(), FPDecimal::TWO); } } diff --git a/packages/injective-math/src/fp_decimal/mod.rs b/packages/injective-math/src/fp_decimal/mod.rs index 5b9d373b..1e0b7b51 100644 --- a/packages/injective-math/src/fp_decimal/mod.rs +++ b/packages/injective-math/src/fp_decimal/mod.rs @@ -384,6 +384,7 @@ impl FPDecimal { mod arithmetic; mod comparison; mod display; +mod error; mod exp; mod factorial; mod from_str; diff --git a/packages/injective-math/src/fp_decimal/scale.rs b/packages/injective-math/src/fp_decimal/scale.rs index e72196f4..d2f0329f 100644 --- a/packages/injective-math/src/fp_decimal/scale.rs +++ b/packages/injective-math/src/fp_decimal/scale.rs @@ -6,7 +6,7 @@ pub trait Scaled { impl Scaled for FPDecimal { fn scaled(self, digits: i32) -> Self { - self.to_owned() * FPDecimal::from(10i128).pow(FPDecimal::from(digits as i128)) + self.to_owned() * FPDecimal::from(10i128).pow(FPDecimal::from(digits as i128)).unwrap() } } diff --git a/packages/injective-math/src/fp_decimal/trigonometry.rs b/packages/injective-math/src/fp_decimal/trigonometry.rs index f8a23e14..6e5d8fb5 100644 --- a/packages/injective-math/src/fp_decimal/trigonometry.rs +++ b/packages/injective-math/src/fp_decimal/trigonometry.rs @@ -7,11 +7,11 @@ impl FPDecimal { } fn _sine_taylor_expansion(x: FPDecimal) -> FPDecimal { - x - (x.pow(FPDecimal::THREE) / FPDecimal::THREE.factorial()) + (x.pow(FPDecimal::FIVE) / FPDecimal::FIVE.factorial()) - - (x.pow(FPDecimal::SEVEN) / FPDecimal::SEVEN.factorial()) - + (x.pow(FPDecimal::NINE) / FPDecimal::NINE.factorial()) - - (x.pow(FPDecimal::ELEVEN) / (FPDecimal::ELEVEN).factorial()) - + (x.pow(FPDecimal::THREE + FPDecimal::TEN) / (FPDecimal::THREE + FPDecimal::TEN).factorial()) + x - (x.pow(FPDecimal::THREE).unwrap() / FPDecimal::THREE.factorial()) + (x.pow(FPDecimal::FIVE).unwrap() / FPDecimal::FIVE.factorial()) + - (x.pow(FPDecimal::SEVEN).unwrap() / FPDecimal::SEVEN.factorial()) + + (x.pow(FPDecimal::NINE).unwrap() / FPDecimal::NINE.factorial()) + - (x.pow(FPDecimal::ELEVEN).unwrap() / (FPDecimal::ELEVEN).factorial()) + + (x.pow(FPDecimal::THREE + FPDecimal::TEN).unwrap() / (FPDecimal::THREE + FPDecimal::TEN).factorial()) } pub(self) fn _sin(mut x: FPDecimal) -> FPDecimal { diff --git a/packages/injective-math/src/root_findings.rs b/packages/injective-math/src/root_findings.rs index a46a901f..963d0cda 100644 --- a/packages/injective-math/src/root_findings.rs +++ b/packages/injective-math/src/root_findings.rs @@ -131,7 +131,7 @@ mod tests { fn test_discrete_newton_2() { let x0 = FPDecimal::TEN; fn func(x0: FPDecimal) -> FPDecimal { - x0.pow(FPDecimal::TWO) + x0.pow(FPDecimal::TWO).unwrap() } let delta = FPDecimal::must_from_str("0.25"); let obj = FPDecimal::FIVE; @@ -146,7 +146,7 @@ mod tests { fn test_discrete_newton_3() { let x0 = FPDecimal::TEN; fn func(x0: FPDecimal) -> FPDecimal { - -x0.pow(FPDecimal::TWO) + FPDecimal::TWO * x0 - FPDecimal::ONE + -x0.pow(FPDecimal::TWO).unwrap() + FPDecimal::TWO * x0 - FPDecimal::ONE } let delta = FPDecimal::ONE / FPDecimal::THREE; let obj = FPDecimal::must_from_str("-15");