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