1use core::f32::consts::{FRAC_1_PI, PI};
9
10const SIGN_MASK: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000;
11
12#[must_use]
14pub fn tan(x: f32) -> f32 {
15 sin(x) / cos(x)
16}
17
18#[must_use]
20pub fn sin(x: f32) -> f32 {
21 cos(x - PI / 2.0)
22}
23
24#[must_use]
26pub fn cos(x: f32) -> f32 {
27 let mut x = x;
29 x *= FRAC_1_PI / 2.0;
30 x -= 0.25 + floor(x + 0.25);
31 x *= 16.0 * (abs(x) - 0.5);
32 x += 0.225 * x * (abs(x) - 1.0);
33 x
34}
35
36#[must_use]
38pub fn floor(x: f32) -> f32 {
39 #[expect(clippy::cast_precision_loss)]
41 let mut res = (x as i32) as f32;
42 if x < res {
43 res -= 1.0;
44 }
45 res
46}
47
48#[must_use]
50pub fn abs(x: f32) -> f32 {
51 f32::from_bits(x.to_bits() & !SIGN_MASK)
53}
54
55#[must_use]
57pub fn sqrt(x: f32) -> f32 {
58 if x >= 0. {
60 f32::from_bits((x.to_bits() + 0x3f80_0000) >> 1)
61 } else {
62 f32::NAN
63 }
64}
65
66#[must_use]
68pub fn rem_euclid(lhs: f32, rhs: f32) -> f32 {
69 let r = lhs % rhs;
71 if r < 0.0 {
72 r + abs(rhs)
73 } else {
74 r
75 }
76}
77
78#[must_use]
79pub fn atan2(lhs: f32, rhs: f32) -> f32 {
80 let n = atan2_norm(lhs, rhs);
82 PI / 2.0 * if n > 2.0 { n - 4.0 } else { n }
83}
84
85#[must_use]
88#[expect(clippy::similar_names)]
89pub(crate) fn atan2_norm(lhs: f32, rhs: f32) -> f32 {
90 const SIGN_MASK: u32 = 0x8000_0000;
91 const B: f32 = 0.596_227;
92
93 let y = lhs;
94 let x = rhs;
95
96 let ux_s = SIGN_MASK & x.to_bits();
98 let uy_s = SIGN_MASK & y.to_bits();
99
100 #[expect(clippy::cast_precision_loss)]
102 let q = ((!ux_s & uy_s) >> 29 | ux_s >> 30) as f32;
103
104 let bxy_a = (B * x * y).abs();
106 let n = bxy_a + y * y;
107 let atan_1q = n / (x * x + bxy_a + n);
108
109 let uatan_2q = (ux_s ^ uy_s) | atan_1q.to_bits();
111 q + f32::from_bits(uatan_2q)
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 #[expect(clippy::float_cmp)]
120 fn test_sqrt() {
121 assert_eq!(sqrt(4.), 2.);
122 assert_eq!(sqrt(9.), 3.125);
123 }
124}