use core::f32::consts::{FRAC_1_PI, FRAC_PI_2, PI};
const SIGN_MASK: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000;
#[must_use]
pub fn tan(x: f32) -> f32 {
sin(x) / cos(x)
}
#[must_use]
pub fn sin(x: f32) -> f32 {
cos(x - PI / 2.0)
}
#[must_use]
pub fn cos(x: f32) -> f32 {
let mut x = x;
x *= FRAC_1_PI / 2.0;
x -= 0.25 + floor(x + 0.25);
x *= 16.0 * (abs(x) - 0.5);
x += 0.225 * x * (abs(x) - 1.0);
x
}
#[must_use]
pub fn floor(x: f32) -> f32 {
#[expect(clippy::cast_precision_loss)]
let mut res = (x as i32) as f32;
if x < res {
res -= 1.0;
}
res
}
#[must_use]
pub fn abs(x: f32) -> f32 {
f32::from_bits(x.to_bits() & !SIGN_MASK)
}
#[must_use]
pub fn sqrt(x: f32) -> f32 {
if x >= 0. {
f32::from_bits((x.to_bits() + 0x3f80_0000) >> 1)
} else {
f32::NAN
}
}
#[must_use]
pub fn rem_euclid(lhs: f32, rhs: f32) -> f32 {
let r = lhs % rhs;
if r < 0.0 {
r + abs(rhs)
} else {
r
}
}
#[must_use]
pub fn atan(x: f32) -> f32 {
FRAC_PI_2 * atan_norm(x)
}
#[must_use]
pub fn atan_norm(x: f32) -> f32 {
const SIGN_MASK: u32 = 0x8000_0000;
const B: f32 = 0.596_227;
let ux_s = SIGN_MASK & x.to_bits();
let bx_a = abs(B * x);
let n = bx_a + x * x;
let atan_1q = n / (1.0 + bx_a + n);
f32::from_bits(ux_s | atan_1q.to_bits())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[expect(clippy::float_cmp)]
fn test_sqrt() {
assert_eq!(sqrt(4.), 2.);
assert_eq!(sqrt(9.), 3.125);
}
}