use super::funejson::Value; // fdlibm's split of ln 2: the high part has trailing zero bits, so e * LN2_HI // is exact for any exponent a double can have. const LN2_HI: f64 = 6.93147180369123816490e-01; const LN2_LO: f64 = 1.90821492927058770002e-10; const SQRT2: f64 = 1.4142135623730951; /// Natural logarithm using only +, -, * and /. /// /// `f64::ln` calls the platform's maths library, whose last bit may differ /// from JavaScript's and Python's. This follows the same steps in the same /// order as the other two, so all three return the same double. /// /// # Panics /// Panics unless `x` is finite and greater than zero. pub fn ln(x: f64) -> f64 { if !x.is_finite() || x <= 0.0 { panic!("ln is only defined for finite numbers greater than zero, received {}", x); } let mut m = x; let mut e = 0i64; while m >= 2.0 { m /= 2.0; e += 1; } while m < 1.0 { m *= 2.0; e -= 1; } if m > SQRT2 { m /= 2.0; e += 1; } let f = m - 1.0; let s = f / (2.0 + f); let z = s * s; let mut p = 1.0 / 25.0; p = 1.0 / 23.0 + z * p; p = 1.0 / 21.0 + z * p; p = 1.0 / 19.0 + z * p; p = 1.0 / 17.0 + z * p; p = 1.0 / 15.0 + z * p; p = 1.0 / 13.0 + z * p; p = 1.0 / 11.0 + z * p; p = 1.0 / 9.0 + z * p; p = 1.0 / 7.0 + z * p; p = 1.0 / 5.0 + z * p; p = 1.0 / 3.0 + z * p; let lnm = 2.0 * s + 2.0 * s * (z * p); let ef = e as f64; ef * LN2_HI + (ef * LN2_LO + lnm) } pub fn fune_vector(args: &[Value]) -> Value { Value::Float(ln(args[0].as_f64())) }