use super::consts::*;
use super::unsigned::UnsignedNumeric;
use super::signed::SignedNumeric;
impl UnsignedNumeric {
pub fn log(&self) -> Option<SignedNumeric> {
if self.eq(&ZERO_PREC) {
return None;
}
if self.eq(&ONE_PREC) {
return Some(SignedNumeric {
value: ZERO_PREC.clone(),
is_negative: false,
});
}
let (f1_init, ki_init) = self.frexp()?;
let (f1, ki) = if f1_init.less_than(&SQRT2OVERTWO) {
let new_f1 = f1_init.checked_mul(&TWO_PREC)?;
let new_k1 = ki_init.checked_sub(1)?;
(new_f1, new_k1)
} else {
(f1_init, ki_init)
};
let f = f1.signed().checked_sub(&UnsignedNumeric::one().signed())?;
let s_divisor = UnsignedNumeric { value: two() }.signed().checked_add(&f)?;
let s = &f.checked_div(&s_divisor)?;
let s2 = s.checked_mul(s)?.value;
let s4 = s2.checked_mul(&s2)?;
let t1 = s2.checked_mul(&L1.checked_add(&s4.checked_mul(
&L3.checked_add(&s4.checked_mul(&L5.checked_add(&s4.checked_mul(&L7)?)?)?)?
)?)?)?;
let t2 = s4.checked_mul(
&L2.checked_add(&s4.checked_mul(&L4.checked_add(&s4.checked_mul(&L6)?)?)?)?,
)?;
let r = t1.checked_add(&t2)?;
let hfsq = f
.checked_mul(&f)?
.checked_div(&UnsignedNumeric { value: two() }.signed())?;
let k = SignedNumeric {
value: UnsignedNumeric::new(u128::try_from(ki.abs()).ok()?),
is_negative: ki < 0,
};
let kl2hi = k
.checked_mul(&LN2HI.signed())?
.checked_div(&LN2HI_SCALE.signed())?;
let shfsqr = s.checked_mul(&hfsq.checked_add(&r.signed())?)?;
let kl2lo = k
.checked_mul(&LN2LO.signed())?
.checked_div(&LN2LO_SCALE.signed())?;
let shfsqr_kl2lo = shfsqr.checked_add(&kl2lo)?;
let hfsq_shfsqr_kl2lo = hfsq.checked_sub(&shfsqr_kl2lo)?;
let f_hfsq_shfsqr_kl2lo = hfsq_shfsqr_kl2lo.checked_sub(&f)?;
kl2hi.checked_sub(&f_hfsq_shfsqr_kl2lo)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::InnerUint;
#[test]
fn test_log() {
let precision = InnerUint::from(5_000_000_000_u128);
let test = UnsignedNumeric::new(9);
let log = test.log().unwrap().value;
let expected = UnsignedNumeric::new(21972245773362196)
.checked_div(&UnsignedNumeric::new(10000000000000000))
.unwrap();
assert!(log.almost_eq(&expected, precision));
let test2 = UnsignedNumeric::new(2);
assert!(test2.log().unwrap().value.almost_eq(
&UnsignedNumeric::new(6931471805599453)
.checked_div(&UnsignedNumeric::new(10000000000000000))
.unwrap(),
precision
));
let test3 = &UnsignedNumeric::new(12)
.checked_div(&UnsignedNumeric::new(10))
.unwrap();
assert!(test3.log().unwrap().value.almost_eq(
&UnsignedNumeric::new(1823215567939546)
.checked_div(&UnsignedNumeric::new(10000000000000000))
.unwrap(),
precision
));
let test5 = &UnsignedNumeric::new(15)
.checked_div(&UnsignedNumeric::new(10))
.unwrap();
assert!(test5.log().unwrap().value.almost_eq(
&UnsignedNumeric::new(4054651081081644)
.checked_div(&UnsignedNumeric::new(10000000000000000))
.unwrap(),
precision
));
let test6 = UnsignedNumeric::new(4)
.checked_div(&UnsignedNumeric::new(1000000))
.unwrap();
assert!(test6.log().unwrap().value.almost_eq(
&UnsignedNumeric::new(12429216196844383)
.checked_div(&UnsignedNumeric::new(1000000000000000))
.unwrap(),
precision
));
}
}