Functional Weave
Code in Rust

math.sin-cos@1.0.0

impl/rust.rs

2,273 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.

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

// pi/2 in two parts (fdlibm): PIO2_1 has 33 significant bits, so k * PIO2_1 is
// exact for every k up to 2^20, which covers the permitted range.
const PIO2_1: f64 = 1.57079632673412561417e+00;
const PIO2_1T: f64 = 6.07710050650619224932e-11;
const INV_PIO2: f64 = 6.36619772367581382433e-01;
const LIMIT: f64 = 1000000.0;

fn sin_small(r: f64) -> f64 {
    let s = r * r;
    let mut p = 1.0 / 355687428096000.0;
    p = -1.0 / 1307674368000.0 + s * p;
    p = 1.0 / 6227020800.0 + s * p;
    p = -1.0 / 39916800.0 + s * p;
    p = 1.0 / 362880.0 + s * p;
    p = -1.0 / 5040.0 + s * p;
    p = 1.0 / 120.0 + s * p;
    p = -1.0 / 6.0 + s * p;
    r + r * s * p
}

fn cos_small(r: f64) -> f64 {
    let s = r * r;
    let mut p = -1.0 / 6402373705728000.0;
    p = 1.0 / 20922789888000.0 + s * p;
    p = -1.0 / 87178291200.0 + s * p;
    p = 1.0 / 479001600.0 + s * p;
    p = -1.0 / 3628800.0 + s * p;
    p = 1.0 / 40320.0 + s * p;
    p = -1.0 / 720.0 + s * p;
    p = 1.0 / 24.0 + s * p;
    p = -1.0 / 2.0 + s * p;
    1.0 + s * p
}

/// Sine and cosine using only +, -, * and /, in the same order as the
/// TypeScript and Python versions, so all three return the same doubles.
/// `f64::sin_cos` calls the platform's maths library, whose last bit may differ.
///
/// # Panics
/// Panics unless `radians` is finite and within -1,000,000..=1,000,000.
pub fn sin_cos(radians: f64) -> SinCos {
    if !radians.is_finite() || radians < -LIMIT || radians > LIMIT {
        panic!("radians must be a finite number between -1000000 and 1000000, received {}", radians);
    }
    let kf = (radians * INV_PIO2 + 0.5).floor();
    let r = radians - kf * PIO2_1 - kf * PIO2_1T;
    let s = sin_small(r);
    let c = cos_small(r);
    let quadrant = ((kf as i64 % 4) + 4) % 4;
    match quadrant {
        0 => SinCos { sin: s + 0.0, cos: c + 0.0 },
        1 => SinCos { sin: c + 0.0, cos: -s + 0.0 },
        2 => SinCos { sin: -s + 0.0, cos: -c + 0.0 },
        _ => SinCos { sin: -c + 0.0, cos: s + 0.0 },
    }
}

pub fn sin_cos_to_value(v: &SinCos) -> Value {
    Value::obj(vec![("sin", Value::Float(v.sin)), ("cos", Value::Float(v.cos))])
}

pub fn fune_vector(args: &[Value]) -> Value {
    sin_cos_to_value(&sin_cos(args[0].as_f64()))
}