Functional Weave
Code in Rust

math.ln@1.0.1

impl/rust.rs

1,899 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

// Derived from fdlibm e_log.c.
// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
// Developed at SunSoft, a Sun Microsystems, Inc. business.
// Permission to use, copy, modify, and distribute this
// software is freely granted, provided that this notice
// is preserved.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one

// 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()))
}