retrofire_core/math/
float.rs1#[cfg(feature = "libm")]
10pub mod libm {
11 pub use libm::floorf as floor;
12
13 pub use libm::powf;
14 pub use libm::sqrtf as sqrt;
15
16 pub use libm::cosf as cos;
17 pub use libm::sinf as sin;
18 pub use libm::tanf as tan;
19
20 pub use libm::acosf as acos;
21 pub use libm::asinf as asin;
22 pub use libm::atan2f as atan2;
23
24 pub use libm::expf as exp;
25 pub use libm::log2;
26
27 pub use super::fallback::rem_euclid;
28
29 pub fn recip_sqrt(x: f32) -> f32 {
30 powf(x, -0.5)
31 }
32}
33
34#[cfg(feature = "mm")]
35pub mod mm {
36 use micromath::F32Ext as mm;
37
38 #[inline]
39 pub fn floor(x: f32) -> f32 {
40 mm::floor(x)
41 }
42 #[inline]
43 pub fn rem_euclid(x: f32, m: f32) -> f32 {
44 mm::rem_euclid(x, m)
45 }
46 #[inline]
48 pub fn sqrt(x: f32) -> f32 {
49 let y = mm::sqrt(x);
50 0.5 * (y + (x / y))
52 }
53 #[inline]
55 pub fn recip_sqrt(x: f32) -> f32 {
56 let y = mm::invsqrt(x);
57 y * (1.5 - 0.5 * x * y * y)
59 }
60 #[inline]
61 pub fn powf(x: f32, y: f32) -> f32 {
62 mm::powf(x, y)
63 }
64 #[inline]
65 pub fn sin(x: f32) -> f32 {
66 mm::sin(x)
67 }
68 #[inline]
69 pub fn cos(x: f32) -> f32 {
70 mm::cos(x)
71 }
72 #[inline]
73 pub fn tan(x: f32) -> f32 {
74 mm::tan(x)
75 }
76 #[inline]
77 pub fn asin(x: f32) -> f32 {
78 mm::asin(x)
79 }
80 #[inline]
81 pub fn acos(x: f32) -> f32 {
82 mm::acos(x)
83 }
84 #[inline]
85 pub fn atan2(y: f32, x: f32) -> f32 {
86 #[cfg(debug_assertions)]
87 if y == 0.0 && x == 0.0 {
88 return 0.0;
90 }
91 mm::atan2(y, x)
92 }
93}
94
95pub mod fallback {
96 #[inline]
98 pub fn floor(x: f32) -> f32 {
99 (x as i64 - x.is_sign_negative() as i64) as f32
100 }
101 #[inline]
103 pub fn rem_euclid(x: f32, m: f32) -> f32 {
104 x % m + (x.is_sign_negative() as u32 as f32) * m
105 }
106 #[inline]
108 pub fn recip_sqrt(x: f32) -> f32 {
109 let y = f32::from_bits(0x5f37_5a86 - (x.to_bits() >> 1));
111 y * (1.5 - 0.5 * x * y * y)
113 }
114}
115
116#[cfg(feature = "std")]
117#[allow(non_camel_case_types)]
118pub type f32 = core::primitive::f32;
119
120#[allow(unused)]
121pub(crate) trait RecipSqrt {
122 fn recip_sqrt(x: Self) -> Self;
123}
124
125#[cfg(feature = "std")]
126impl RecipSqrt for f32 {
127 fn recip_sqrt(x: f32) -> f32 {
128 x.powf(-0.5)
129 }
130}
131
132#[cfg(all(feature = "libm", not(feature = "std")))]
133pub use libm as f32;
134
135#[cfg(all(feature = "mm", not(feature = "std"), not(feature = "libm")))]
136pub use mm as f32;
137
138#[cfg(not(feature = "fp"))]
139pub use fallback as f32;
140
141#[cfg(test)]
142#[allow(unused_imports)]
143mod tests {
144
145 use crate::assert_approx_eq;
146
147 #[cfg(feature = "libm")]
148 #[test]
149 fn libm_functions() {
150 use super::libm;
151 use core::f32::consts::PI;
152 assert_eq!(libm::cos(PI), -1.0);
153 assert_eq!(libm::sqrt(9.0), 3.0);
154 }
155
156 #[cfg(feature = "mm")]
157 #[test]
158 fn mm_functions() {
159 use core::f32::consts::*;
160
161 use super::f32;
162
163 assert_approx_eq!(f32::sin(FRAC_PI_6), 0.5);
164 assert_eq!(f32::cos(PI), -1.0);
165 assert_eq!(f32::sqrt(16.0), 4.0);
166 assert_approx_eq!(f32::sqrt(9.0), 3.0, eps = 1e-3);
167 }
168
169 #[cfg(feature = "std")]
170 #[test]
171 fn std_functions() {
172 use super::f32;
173 use core::f32::consts::PI;
174 assert_eq!(f32::cos(PI), -1.0);
175 assert_eq!(f32::sqrt(9.0), 3.0);
176 }
177
178 #[cfg(not(feature = "fp"))]
179 #[test]
180 fn fallback_functions() {
181 use super::{RecipSqrt, f32};
182
183 assert_eq!(f32::floor(1.23), 1.0);
184 assert_eq!(f32::floor(0.0), 0.0);
185 assert_eq!(f32::floor(-1.23), -2.0);
186
187 assert_approx_eq!(f32::rem_euclid(1.23, 4.0), 1.23);
188 assert_approx_eq!(f32::rem_euclid(4.0, 4.0), 0.0);
189 assert_approx_eq!(f32::rem_euclid(5.67, 4.0), 1.67);
190 assert_approx_eq!(f32::rem_euclid(-1.23, 4.0), 2.77);
191 }
192
193 #[test]
194 fn recip_sqrt() {
195 use super::{RecipSqrt, f32};
196 assert_approx_eq!(f32::recip_sqrt(2.0), f32::sqrt(0.5), eps = 1e-2);
197 assert_approx_eq!(f32::recip_sqrt(9.0), 1.0 / 3.0, eps = 1e-3);
198 }
199}