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
// fdlibm s_atan.c (Sun Microsystems, 1993). atan of 0.5, 1, 1.5 and infinity,
// each split into a high and a low part so the sum carries more than 53 bits.
const ATAN_HI: [f64; 4] = [
4.63647609000806093515e-01,
7.85398163397448278999e-01,
9.82793723247329054082e-01,
1.57079632679489655800e+00,
];
const ATAN_LO: [f64; 4] = [
2.26987774529616870924e-17,
3.06161699786838301793e-17,
1.39033110312309984516e-17,
6.12323399573676603587e-17,
];
const AT: [f64; 11] = [
3.33333333333329318027e-01,
-1.99999999998764832476e-01,
1.42857142725034663711e-01,
-1.11111104054623557880e-01,
9.09088713343650656196e-02,
-7.69187620504482999495e-02,
6.66107313738753120669e-02,
-5.83357013379057348645e-02,
4.97687799461593236017e-02,
-3.65315727442169155270e-02,
1.62858201153657823623e-02,
];
const TWO_POW_66: f64 = 73786976294838206464.0;
const TWO_POW_M29: f64 = 1.862645149230957e-9;
/// Arctangent in radians using only +, -, * and /, in the same order as the
/// TypeScript and Python versions, so all three return the same double.
/// `f64::atan` calls the platform's maths library, whose last bit may differ.
///
/// fdlibm's method: reduce |x| against atan(0.5), atan(1), atan(1.5) or pi/2,
/// then an odd polynomial on the remainder. fdlibm picks the interval from the
/// high word of the double; comparing |x| with the same boundaries (7/16,
/// 11/16, 19/16, 39/16, 2^66, 2^-29) is exactly equivalent.
///
/// # Panics
/// Panics if `x` is not finite.
pub fn atan(x: f64) -> f64 {
if !x.is_finite() {
panic!("x must be a finite number, received {}", x);
}
let negative = x < 0.0;
let a = if negative { -x } else { x };
if a >= TWO_POW_66 {
let r = ATAN_HI[3] + ATAN_LO[3];
return if negative { -r } else { r };
}
let i: usize;
let mut t = x;
let reduced: bool;
if a < 0.4375 {
// atan(x) rounds to x here; + 0.0 turns -0 into 0.
if a < TWO_POW_M29 {
return x + 0.0;
}
reduced = false;
i = 0;
} else {
reduced = true;
t = a;
if a < 1.1875 {
if a < 0.6875 {
i = 0;
t = (2.0 * t - 1.0) / (2.0 + t);
} else {
i = 1;
t = (t - 1.0) / (t + 1.0);
}
} else if a < 2.4375 {
i = 2;
t = (t - 1.5) / (1.0 + 1.5 * t);
} else {
i = 3;
t = -1.0 / t;
}
}
let z = t * t;
let w = z * z;
let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10])))));
let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9]))));
if !reduced {
return t - t * (s1 + s2);
}
let r = ATAN_HI[i] - ((t * (s1 + s2) - ATAN_LO[i]) - t);
if negative {
-r
} else {
r
}
}
pub fn fune_vector(args: &[Value]) -> Value {
// JSON can carry a string where the number goes; TypeScript and Python
// refuse it, so Rust does too rather than letting the adapter convert it.
if let Value::Str(s) = &args[0] {
panic!("x must be a finite number, received \"{}\"", s);
}
Value::Float(atan(args[0].as_f64()))
}