1 /// Returns a very close approximation of `self.clamp(-1.0, 1.0).acos()`.
2 #[inline]
acos_approx_f32(v: f32) -> f323 fn acos_approx_f32(v: f32) -> f32 {
4 // Based on https://github.com/microsoft/DirectXMath `XMScalarAcos`
5 // Clamp input to [-1,1].
6 let nonnegative = v >= 0.0;
7 let x = abs(v);
8 let mut omx = 1.0 - x;
9 if omx < 0.0 {
10 omx = 0.0;
11 }
12 let root = sqrt(omx);
13
14 // 7-degree minimax approximation
15 #[allow(clippy::approx_constant)]
16 let mut result =
17 ((((((-0.001_262_491_1 * x + 0.006_670_09) * x - 0.017_088_126) * x + 0.030_891_88) * x
18 - 0.050_174_303)
19 * x
20 + 0.088_978_99)
21 * x
22 - 0.214_598_8)
23 * x
24 + 1.570_796_3;
25 result *= root;
26
27 // acos(x) = pi - acos(-x) when x < 0
28 if nonnegative {
29 result
30 } else {
31 core::f32::consts::PI - result
32 }
33 }
34
35 #[cfg(feature = "libm")]
36 mod libm_math {
37 #[inline(always)]
abs(f: f32) -> f3238 pub(crate) fn abs(f: f32) -> f32 {
39 libm::fabsf(f)
40 }
41
42 #[inline(always)]
acos_approx(f: f32) -> f3243 pub(crate) fn acos_approx(f: f32) -> f32 {
44 super::acos_approx_f32(f)
45 }
46
47 #[inline(always)]
atan2(f: f32, other: f32) -> f3248 pub(crate) fn atan2(f: f32, other: f32) -> f32 {
49 libm::atan2f(f, other)
50 }
51
52 #[allow(unused)]
53 #[inline(always)]
sin(f: f32) -> f3254 pub(crate) fn sin(f: f32) -> f32 {
55 libm::sinf(f)
56 }
57
58 #[inline(always)]
sin_cos(f: f32) -> (f32, f32)59 pub(crate) fn sin_cos(f: f32) -> (f32, f32) {
60 libm::sincosf(f)
61 }
62
63 #[inline(always)]
tan(f: f32) -> f3264 pub(crate) fn tan(f: f32) -> f32 {
65 libm::tanf(f)
66 }
67
68 #[inline(always)]
sqrt(f: f32) -> f3269 pub(crate) fn sqrt(f: f32) -> f32 {
70 libm::sqrtf(f)
71 }
72
73 #[inline(always)]
copysign(f: f32, sign: f32) -> f3274 pub(crate) fn copysign(f: f32, sign: f32) -> f32 {
75 libm::copysignf(f, sign)
76 }
77
78 #[inline(always)]
signum(f: f32) -> f3279 pub(crate) fn signum(f: f32) -> f32 {
80 if f.is_nan() {
81 f32::NAN
82 } else {
83 copysign(1.0, f)
84 }
85 }
86
87 #[inline(always)]
round(f: f32) -> f3288 pub(crate) fn round(f: f32) -> f32 {
89 libm::roundf(f)
90 }
91
92 #[inline(always)]
trunc(f: f32) -> f3293 pub(crate) fn trunc(f: f32) -> f32 {
94 libm::truncf(f)
95 }
96
97 #[inline(always)]
ceil(f: f32) -> f3298 pub(crate) fn ceil(f: f32) -> f32 {
99 libm::ceilf(f)
100 }
101
102 #[inline(always)]
floor(f: f32) -> f32103 pub(crate) fn floor(f: f32) -> f32 {
104 libm::floorf(f)
105 }
106
107 #[inline(always)]
exp(f: f32) -> f32108 pub(crate) fn exp(f: f32) -> f32 {
109 libm::expf(f)
110 }
111
112 #[inline(always)]
powf(f: f32, n: f32) -> f32113 pub(crate) fn powf(f: f32, n: f32) -> f32 {
114 libm::powf(f, n)
115 }
116
117 #[inline(always)]
mul_add(a: f32, b: f32, c: f32) -> f32118 pub(crate) fn mul_add(a: f32, b: f32, c: f32) -> f32 {
119 libm::fmaf(a, b, c)
120 }
121
122 #[inline]
div_euclid(a: f32, b: f32) -> f32123 pub fn div_euclid(a: f32, b: f32) -> f32 {
124 // Based on https://doc.rust-lang.org/src/std/f32.rs.html#293
125 let q = libm::truncf(a / b);
126 if a % b < 0.0 {
127 return if b > 0.0 { q - 1.0 } else { q + 1.0 };
128 }
129 q
130 }
131
132 #[inline]
rem_euclid(a: f32, b: f32) -> f32133 pub fn rem_euclid(a: f32, b: f32) -> f32 {
134 let r = a % b;
135 if r < 0.0 {
136 r + abs(b)
137 } else {
138 r
139 }
140 }
141 }
142
143 #[cfg(all(not(feature = "libm"), feature = "std"))]
144 mod std_math {
145 #[inline(always)]
abs(f: f32) -> f32146 pub(crate) fn abs(f: f32) -> f32 {
147 f32::abs(f)
148 }
149
150 #[inline(always)]
acos_approx(f: f32) -> f32151 pub(crate) fn acos_approx(f: f32) -> f32 {
152 super::acos_approx_f32(f)
153 }
154
155 #[inline(always)]
atan2(f: f32, other: f32) -> f32156 pub(crate) fn atan2(f: f32, other: f32) -> f32 {
157 f32::atan2(f, other)
158 }
159
160 #[allow(unused)]
161 #[inline(always)]
sin(f: f32) -> f32162 pub(crate) fn sin(f: f32) -> f32 {
163 f32::sin(f)
164 }
165
166 #[inline(always)]
sin_cos(f: f32) -> (f32, f32)167 pub(crate) fn sin_cos(f: f32) -> (f32, f32) {
168 f32::sin_cos(f)
169 }
170
171 #[inline(always)]
tan(f: f32) -> f32172 pub(crate) fn tan(f: f32) -> f32 {
173 f32::tan(f)
174 }
175
176 #[inline(always)]
sqrt(f: f32) -> f32177 pub(crate) fn sqrt(f: f32) -> f32 {
178 f32::sqrt(f)
179 }
180
181 #[inline(always)]
copysign(f: f32, sign: f32) -> f32182 pub(crate) fn copysign(f: f32, sign: f32) -> f32 {
183 f32::copysign(f, sign)
184 }
185
186 #[inline(always)]
signum(f: f32) -> f32187 pub(crate) fn signum(f: f32) -> f32 {
188 f32::signum(f)
189 }
190
191 #[inline(always)]
round(f: f32) -> f32192 pub(crate) fn round(f: f32) -> f32 {
193 f32::round(f)
194 }
195
196 #[inline(always)]
trunc(f: f32) -> f32197 pub(crate) fn trunc(f: f32) -> f32 {
198 f32::trunc(f)
199 }
200
201 #[inline(always)]
ceil(f: f32) -> f32202 pub(crate) fn ceil(f: f32) -> f32 {
203 f32::ceil(f)
204 }
205
206 #[inline(always)]
floor(f: f32) -> f32207 pub(crate) fn floor(f: f32) -> f32 {
208 f32::floor(f)
209 }
210
211 #[inline(always)]
exp(f: f32) -> f32212 pub(crate) fn exp(f: f32) -> f32 {
213 f32::exp(f)
214 }
215
216 #[inline(always)]
powf(f: f32, n: f32) -> f32217 pub(crate) fn powf(f: f32, n: f32) -> f32 {
218 f32::powf(f, n)
219 }
220
221 #[inline(always)]
mul_add(a: f32, b: f32, c: f32) -> f32222 pub(crate) fn mul_add(a: f32, b: f32, c: f32) -> f32 {
223 f32::mul_add(a, b, c)
224 }
225
226 #[inline]
div_euclid(a: f32, b: f32) -> f32227 pub fn div_euclid(a: f32, b: f32) -> f32 {
228 f32::div_euclid(a, b)
229 }
230
231 #[inline]
rem_euclid(a: f32, b: f32) -> f32232 pub fn rem_euclid(a: f32, b: f32) -> f32 {
233 f32::rem_euclid(a, b)
234 }
235 }
236
237 // Used to reduce the number of compilation errors, in the event that no other
238 // math backend is specified.
239 #[cfg(all(not(feature = "libm"), not(feature = "std")))]
240 mod no_backend_math {
abs(_: f32) -> f32241 pub(crate) fn abs(_: f32) -> f32 {
242 unimplemented!()
243 }
244
acos_approx(_: f32) -> f32245 pub(crate) fn acos_approx(_: f32) -> f32 {
246 unimplemented!()
247 }
248
atan2(_: f32, _: f32) -> f32249 pub(crate) fn atan2(_: f32, _: f32) -> f32 {
250 unimplemented!()
251 }
252
sin(_: f32) -> f32253 pub(crate) fn sin(_: f32) -> f32 {
254 unimplemented!()
255 }
256
sin_cos(_: f32) -> (f32, f32)257 pub(crate) fn sin_cos(_: f32) -> (f32, f32) {
258 unimplemented!()
259 }
260
tan(_: f32) -> f32261 pub(crate) fn tan(_: f32) -> f32 {
262 unimplemented!()
263 }
264
sqrt(_: f32) -> f32265 pub(crate) fn sqrt(_: f32) -> f32 {
266 unimplemented!()
267 }
268
copysign(_: f32, _: f32) -> f32269 pub(crate) fn copysign(_: f32, _: f32) -> f32 {
270 unimplemented!()
271 }
272
signum(_: f32) -> f32273 pub(crate) fn signum(_: f32) -> f32 {
274 unimplemented!()
275 }
276
round(_: f32) -> f32277 pub(crate) fn round(_: f32) -> f32 {
278 unimplemented!()
279 }
280
trunc(_: f32) -> f32281 pub(crate) fn trunc(_: f32) -> f32 {
282 unimplemented!()
283 }
284
ceil(_: f32) -> f32285 pub(crate) fn ceil(_: f32) -> f32 {
286 unimplemented!()
287 }
288
floor(_: f32) -> f32289 pub(crate) fn floor(_: f32) -> f32 {
290 unimplemented!()
291 }
292
exp(_: f32) -> f32293 pub(crate) fn exp(_: f32) -> f32 {
294 unimplemented!()
295 }
296
powf(_: f32, _: f32) -> f32297 pub(crate) fn powf(_: f32, _: f32) -> f32 {
298 unimplemented!()
299 }
300
mul_add(_: f32, _: f32, _: f32) -> f32301 pub(crate) fn mul_add(_: f32, _: f32, _: f32) -> f32 {
302 unimplemented!()
303 }
304
div_euclid(_: f32, _: f32) -> f32305 pub fn div_euclid(_: f32, _: f32) -> f32 {
306 unimplemented!()
307 }
308
rem_euclid(_: f32, _: f32) -> f32309 pub fn rem_euclid(_: f32, _: f32) -> f32 {
310 unimplemented!()
311 }
312 }
313
314 #[cfg(feature = "libm")]
315 pub(crate) use libm_math::*;
316
317 #[cfg(all(not(feature = "libm"), feature = "std"))]
318 pub(crate) use std_math::*;
319
320 #[cfg(all(not(feature = "libm"), not(feature = "std")))]
321 pub(crate) use no_backend_math::*;
322