use crate::defs::BigFloatNum;
use crate::defs::Error;
use crate::defs::DECIMAL_BASE;
use crate::defs::DECIMAL_PARTS;
use crate::defs::DECIMAL_POSITIONS;
impl BigFloatNum {
pub fn ln(&self) -> Result<Self, Error> {
let arg = Self::to_big_float_inc(self);
let ret = arg.ln()?;
Self::from_big_float_inc(ret)
}
pub fn exp(&self) -> Result<Self, Error> {
let arg = Self::to_big_float_inc(self);
let ret = arg.exp()?;
Self::from_big_float_inc(ret)
}
pub fn log(&self, b: &Self) -> Result<Self, Error> {
let arg = Self::to_big_float_inc(self);
let base = Self::to_big_float_inc(b);
let ret = arg.log(&base)?;
Self::from_big_float_inc(ret)
}
pub fn log2(&self) -> Result<Self, Error> {
let mut two = Self::new();
two.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 5;
two.n = DECIMAL_POSITIONS as i16;
two.e = 1 - DECIMAL_POSITIONS as i8;
self.log(&two)
}
pub fn log10(&self) -> Result<Self, Error> {
let mut ten = Self::new();
ten.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10;
ten.n = DECIMAL_POSITIONS as i16;
ten.e = 2 - DECIMAL_POSITIONS as i8;
self.log(&ten)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::defs::DECIMAL_POSITIONS;
use crate::defs::DECIMAL_SIGN_NEG;
use crate::defs::E;
#[test]
fn test_log() {
let mut d1;
let mut d2;
let one = BigFloatNum::one();
let two = one.add(&one).unwrap();
let mut epsilon = BigFloatNum::one();
epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8);
d1 = BigFloatNum::new();
assert!(d1.ln().unwrap_err() == Error::InvalidArgument);
assert!(d1.log(&two).unwrap_err() == Error::InvalidArgument);
assert!(two.log(&d1).unwrap_err() == Error::InvalidArgument);
d1 = BigFloatNum::one();
d1.sign = DECIMAL_SIGN_NEG;
assert!(d1.ln().unwrap_err() == Error::InvalidArgument);
assert!(d1.log(&two).unwrap_err() == Error::InvalidArgument);
assert!(two.log(&d1).unwrap_err() == Error::InvalidArgument);
epsilon.e = -77; assert!(E.ln().unwrap().sub(&one).unwrap().abs().cmp(&epsilon) <= 0);
let four = two.add(&two).unwrap();
assert!(
four.log(&two)
.unwrap()
.sub(&two)
.unwrap()
.abs()
.cmp(&epsilon)
<= 0
);
let half = one.div(&two).unwrap();
assert!(
four.log(&half)
.unwrap()
.add(&two)
.unwrap()
.abs()
.cmp(&epsilon)
<= 0
);
assert!(four.log(&one).unwrap_err() == Error::DivisionByZero);
d2 = BigFloatNum::new();
d2.m[0] = 4567;
d2.m[1] = 123;
d2.m[2] = 6789;
d2.m[3] = 2345;
d2.m[4] = 651;
d2.m[5] = 41;
d2.m[6] = 671;
d2.m[7] = 9999;
d2.m[8] = 0;
d2.m[9] = 0;
d2.e = -10;
for i in 1..1000 {
d2.m[2] = i;
d2.m[9] = i;
d2.n = if i < 10 {
1
} else if i < 100 {
2
} else if i < 1000 {
3
} else {
4
} + 36;
d2.e = -50 + (i % 100) as i8;
epsilon.e = -epsilon.n as i8 + 4 - (DECIMAL_POSITIONS as i8) + d2.e + d2.n as i8;
let ret = d2.ln().unwrap();
d1 = ret.exp().unwrap();
assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0);
let ret = d2.log(&two).unwrap();
d1 = two.pow(&ret).unwrap();
assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0);
let ret = d2.log(&half).unwrap();
d1 = half.pow(&ret).unwrap();
assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0);
}
epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8);
assert!(four.log2().unwrap().sub(&two).unwrap().abs().cmp(&epsilon) <= 0);
d1 = BigFloatNum::new();
d1.m[0] = 100;
d1.n = 3;
assert!(d1.log10().unwrap().sub(&two).unwrap().abs().cmp(&epsilon) <= 0);
}
}