Skip to content

Commit

Permalink
wip ln
Browse files Browse the repository at this point in the history
  • Loading branch information
DrunkRandomWalker committed Oct 20, 2023
1 parent 81af2b2 commit 85e8c58
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 64 deletions.
115 changes: 76 additions & 39 deletions packages/injective-math/src/fp_decimal/exp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Vec<FPDecimal>>()
.iter()
.sum::<FPDecimal>()
+ FPDecimal::ONE
+ a.ln() * b
}
// e^(a)
pub fn _exp(a: FPDecimal) -> FPDecimal {
Expand Down Expand Up @@ -416,33 +444,33 @@ 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
Ordering::Less => {
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<FPDecimal, OverflowError> {
fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result<FPDecimal, OverflowError> {
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 {
Expand Down Expand Up @@ -487,7 +515,7 @@ impl FPDecimal {

type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option<FPDecimal>, FPDecimal);

fn compute_negative_exponent_less_one(base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result<FPDecimal, OverflowError> {
fn compute_negative_exponent_less_one(base: FPDecimal, exponent: FPDecimal) -> Result<FPDecimal, OverflowError> {
// 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 {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -551,7 +579,7 @@ impl FPDecimal {
None
}

fn compute_positive_exponent_less_one(base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result<FPDecimal, OverflowError> {
fn compute_positive_exponent_less_one(base: FPDecimal, exponent: FPDecimal) -> Result<FPDecimal, OverflowError> {
// 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");
Expand All @@ -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 {
Expand All @@ -597,12 +625,12 @@ impl FPDecimal {
base * temp_base
}

fn compute_positive_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result<FPDecimal, OverflowError> {
fn compute_positive_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result<FPDecimal, OverflowError> {
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
};
Expand Down Expand Up @@ -936,28 +964,27 @@ impl FPDecimal {
fn compute_exponentiation(base: FPDecimal, mut exponent: FPDecimal) -> Result<FPDecimal, OverflowError> {
// 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),
},
}
}

type BaseCheckFunction<'a> = (&'a dyn Fn(FPDecimal) -> Option<FPDecimal>, FPDecimal);

fn compute_negative_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result<FPDecimal, OverflowError> {
fn compute_negative_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal) -> Result<FPDecimal, OverflowError> {
// NOTE: only accurate for 1,3,5,7,11, and combinations of these numbers
base = -base;

Expand All @@ -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 {
Expand All @@ -1008,20 +1035,20 @@ impl FPDecimal {
}
}

fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal, n_terms: u128) -> Result<FPDecimal, OverflowError> {
fn compute_negative_exponent_greater_one(mut base: FPDecimal, exponent: FPDecimal) -> Result<FPDecimal, OverflowError> {
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
};
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, n_terms: u128) -> Result<FPDecimal, OverflowError> {
fn compute_positive_exponent_less_one(mut base: FPDecimal, exponent: FPDecimal) -> Result<FPDecimal, OverflowError> {
// 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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down
36 changes: 25 additions & 11 deletions packages/injective-math/src/fp_decimal/from_str.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<Self, Self::Err> {
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::<Vec<&str>>();
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,
Expand All @@ -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,
Expand All @@ -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

Check failure on line 56 in packages/injective-math/src/fp_decimal/from_str.rs

View workflow job for this annotation

GitHub Actions / Lints

returning the result of a `let` binding from a block
}
}

#[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");
Expand Down
Loading

0 comments on commit 85e8c58

Please sign in to comment.