1use std::{
2 f64::consts::PI,
3 ops::{Add, Div, Sub},
4 sync::LazyLock,
5};
6
7pub const EPSILON: f64 = 1.0E-7;
8
9pub static SIN: LazyLock<[f32; 65536]> =
10 LazyLock::new(|| std::array::from_fn(|i| f64::sin((i as f64) * PI * 2. / 65536.) as f32));
11
12pub fn sin(x: f32) -> f32 {
14 let x = x * 10430.378;
15 let x = x as i32 as usize & 0xFFFF;
16 SIN[x]
17}
18
19pub fn cos(x: f32) -> f32 {
21 let x = x * 10430.378 + 16384.;
22 let x = x as i32 as usize & 0xFFFF;
23 SIN[x]
24}
25
26pub fn binary_search<
27 T: Ord + PartialOrd + Add<Output = T> + Sub<Output = T> + Div<Output = T> + From<u8> + Copy,
28>(
29 mut min: T,
30 max: T,
31 predicate: impl Fn(T) -> bool,
32) -> T {
33 let mut diff = max - min;
34 while diff > T::from(0) {
35 let diff_mid = diff / T::from(2);
36 let mid = min + diff_mid;
37 if predicate(mid) {
38 diff = diff_mid;
39 } else {
40 min = mid + T::from(1);
41 diff = diff - (diff_mid + T::from(1));
42 }
43 }
44
45 min
46}
47
48pub fn lcm(a: u32, b: u32) -> u64 {
49 let gcd = gcd(a, b);
50 (a as u64) * (b / gcd) as u64
51}
52pub fn gcd(mut a: u32, mut b: u32) -> u32 {
53 while b != 0 {
54 let t = b;
55 b = a % b;
56 a = t;
57 }
58 a
59}
60
61pub fn lerp<T: num_traits::Float>(amount: T, a: T, b: T) -> T {
62 a + amount * (b - a)
63}
64
65pub fn ceil_log2(x: u32) -> u32 {
66 u32::BITS - x.leading_zeros()
67}
68
69pub fn fract(x: f64) -> f64 {
70 let x_int = x as i64 as f64;
71 let floor = if x < x_int { x_int - 1. } else { x_int };
72 x - floor
73}
74
75pub fn to_radians(degrees: f64) -> f64 {
78 degrees * 0.017453292519943295
79}
80pub fn to_degrees(radians: f64) -> f64 {
81 radians * 57.29577951308232
82}
83
84pub fn sign(num: f64) -> f64 {
89 if num == 0. { 0. } else { num.signum() }
90}
91pub fn sign_as_int(num: f64) -> i32 {
92 if num == 0. { 0 } else { num.signum() as i32 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_gcd() {
101 assert_eq!(gcd(0, 0), 0);
102 assert_eq!(gcd(1, 1), 1);
103
104 assert_eq!(gcd(0, 1), 1);
105 assert_eq!(gcd(1, 0), 1);
106
107 assert_eq!(gcd(12, 8), 4);
108 assert_eq!(gcd(8, 12), 4);
109
110 assert_eq!(gcd(12, 9), 3);
111 assert_eq!(gcd(9, 12), 3);
112
113 assert_eq!(gcd(12, 7), 1);
114 assert_eq!(gcd(7, 12), 1);
115 }
116
117 #[test]
118 fn test_sin() {
119 const PI: f32 = std::f32::consts::PI;
120 fn assert_sin_eq_enough(number: f32) {
122 let a = sin(number);
123 let b = f32::sin(number);
124 assert!((a - b).abs() < 0.01, "sin({number}) failed, {a} != {b}");
125 }
126 assert_sin_eq_enough(0.0);
127 assert_sin_eq_enough(PI / 2.0);
128 assert_sin_eq_enough(PI);
129 assert_sin_eq_enough(PI * 2.0);
130 assert_sin_eq_enough(PI * 3.0 / 2.0);
131 assert_sin_eq_enough(-PI / 2.0);
132 assert_sin_eq_enough(-PI);
133 assert_sin_eq_enough(-PI * 2.0);
134 assert_sin_eq_enough(-PI * 3.0 / 2.0);
135 }
136}