use std::f32::consts::{FRAC_2_PI, FRAC_PI_2, FRAC_PI_6, LN_2, LOG2_E, SQRT_2};
pub const LOG2_10: f32 = std::f32::consts::LOG2_10;
const LN_2_OVER_16: f32 = LN_2 / 16.0;
const SQRT_3: f32 = 1.732_050_8;
const TAN_PI_12: f32 = 0.267_949_2;
const PIO2_HI: f32 = FRAC_PI_2;
const PIO2_LO: f32 = -4.371_139e-8;
static TWO_POW_J_16: [f32; 16] = [
1.0,
1.044_273_7,
1.090_507_7,
1.138_788_6,
1.189_207_1,
1.241_857_8,
1.296_839_6,
1.354_255_6,
SQRT_2,
1.476_826_2,
1.542_210_8,
1.610_490_3,
1.681_792_9,
1.756_252_2,
1.834_008_1,
1.915_206_6,
];
pub fn exp2(x: f32) -> f32 {
let y = x * 16.0;
if y < -2400.0 {
return 0.0; }
let n = y.floor() as i32;
let r = (y - n as f32) * LN_2_OVER_16;
let q = n.div_euclid(16);
let j = n.rem_euclid(16) as usize;
let scale = if q < -126 {
2f32.powi(q + 64) * 5.421_011e-20 } else {
2f32.powi(q) };
let p = 1.0 + r * (1.0 + r * (0.5 + r * (1.0 / 6.0 + r * (1.0 / 24.0 + r * (1.0 / 120.0)))));
scale * TWO_POW_J_16[j] * p
}
pub fn log2(x: f32) -> f32 {
debug_assert!(x > 0.0);
let (x, bias) = if x < f32::MIN_POSITIVE {
(x * 16_777_216.0, -24)
} else {
(x, 0)
};
let bits = x.to_bits();
let mut e = ((bits >> 23) & 0xff) as i32 - 127 + bias;
let mut m = f32::from_bits((bits & 0x007f_ffff) | 0x3f80_0000); if m >= SQRT_2 {
m *= 0.5; e += 1;
}
let t = (m - 1.0) / (m + 1.0);
let t2 = t * t;
let s = t * (1.0 + t2 * (1.0 / 3.0 + t2 * (1.0 / 5.0 + t2 * (1.0 / 7.0 + t2 * (1.0 / 9.0)))));
e as f32 + 2.0 * LOG2_E * s
}
pub fn atan(x: f32) -> f32 {
if x < 0.0 {
return -atan(-x);
}
if x > 1.0 {
return FRAC_PI_2 - atan(1.0 / x);
}
let (t, shift) = if x > TAN_PI_12 {
((x * SQRT_3 - 1.0) / (x + SQRT_3), FRAC_PI_6)
} else {
(x, 0.0)
};
shift + atan_poly(t)
}
fn atan_poly(t: f32) -> f32 {
let t2 = t * t;
t * (1.0
+ t2 * (-1.0 / 3.0
+ t2 * (1.0 / 5.0
+ t2 * (-1.0 / 7.0 + t2 * (1.0 / 9.0 + t2 * (-1.0 / 11.0 + t2 * (1.0 / 13.0)))))))
}
pub fn sincos(a: f32) -> (f32, f32) {
debug_assert!((0.0..std::f32::consts::TAU).contains(&a));
let k = (a * FRAC_2_PI + 0.5).floor() as i32;
let kf = k as f32;
let r = (a - kf * PIO2_HI) - kf * PIO2_LO;
let (s, c) = (sin_poly(r), cos_poly(r));
match k.rem_euclid(4) {
0 => (s, c),
1 => (c, -s),
2 => (-s, -c),
_ => (-c, s),
}
}
fn sin_poly(r: f32) -> f32 {
let r2 = r * r;
r * (1.0
+ r2 * (-1.0 / 6.0
+ r2 * (1.0 / 120.0
+ r2 * (-1.0 / 5040.0
+ r2 * (1.0 / 362_880.0 + r2 * (-1.0 / 39_916_800.0 + r2 / 6_227_020_800.0))))))
}
fn cos_poly(r: f32) -> f32 {
let r2 = r * r;
1.0 + r2
* (-1.0 / 2.0
+ r2 * (1.0 / 24.0
+ r2 * (-1.0 / 720.0
+ r2 * (1.0 / 40_320.0 + r2 * (-1.0 / 3_628_800.0 + r2 / 479_001_600.0)))))
}
pub fn pow_three_quarter(x: f32) -> f32 {
let r = x.abs().sqrt();
r * r.sqrt()
}
pub fn twiddle_table(n: usize) -> (Vec<f32>, Vec<f32>) {
let mut re = Vec::with_capacity(n);
let mut im = Vec::with_capacity(n);
let mut len = 2usize;
while len <= n {
let half = len / 2;
let ang = 2.0 * std::f32::consts::PI / len as f32;
for k in 0..half {
let (s, c) = sincos(ang * k as f32);
re.push(c);
im.push(s);
}
len *= 2;
}
(re, im)
}
#[cfg(test)]
#[path = "det_math_tests.rs"]
mod det_math_tests;