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)]
asin(f: f32) -> f3248     pub(crate) fn asin(f: f32) -> f32 {
49         libm::asinf(f)
50     }
51 
52     #[inline(always)]
atan2(f: f32, other: f32) -> f3253     pub(crate) fn atan2(f: f32, other: f32) -> f32 {
54         libm::atan2f(f, other)
55     }
56 
57     #[allow(unused)]
58     #[inline(always)]
sin(f: f32) -> f3259     pub(crate) fn sin(f: f32) -> f32 {
60         libm::sinf(f)
61     }
62 
63     #[inline(always)]
sin_cos(f: f32) -> (f32, f32)64     pub(crate) fn sin_cos(f: f32) -> (f32, f32) {
65         libm::sincosf(f)
66     }
67 
68     #[inline(always)]
tan(f: f32) -> f3269     pub(crate) fn tan(f: f32) -> f32 {
70         libm::tanf(f)
71     }
72 
73     #[inline(always)]
sqrt(f: f32) -> f3274     pub(crate) fn sqrt(f: f32) -> f32 {
75         libm::sqrtf(f)
76     }
77 
78     #[inline(always)]
copysign(f: f32, sign: f32) -> f3279     pub(crate) fn copysign(f: f32, sign: f32) -> f32 {
80         libm::copysignf(f, sign)
81     }
82 
83     #[inline(always)]
signum(f: f32) -> f3284     pub(crate) fn signum(f: f32) -> f32 {
85         if f.is_nan() {
86             f32::NAN
87         } else {
88             copysign(1.0, f)
89         }
90     }
91 
92     #[inline(always)]
round(f: f32) -> f3293     pub(crate) fn round(f: f32) -> f32 {
94         libm::roundf(f)
95     }
96 
97     #[inline(always)]
trunc(f: f32) -> f3298     pub(crate) fn trunc(f: f32) -> f32 {
99         libm::truncf(f)
100     }
101 
102     #[inline(always)]
ceil(f: f32) -> f32103     pub(crate) fn ceil(f: f32) -> f32 {
104         libm::ceilf(f)
105     }
106 
107     #[inline(always)]
floor(f: f32) -> f32108     pub(crate) fn floor(f: f32) -> f32 {
109         libm::floorf(f)
110     }
111 
112     #[inline(always)]
exp(f: f32) -> f32113     pub(crate) fn exp(f: f32) -> f32 {
114         libm::expf(f)
115     }
116 
117     #[inline(always)]
powf(f: f32, n: f32) -> f32118     pub(crate) fn powf(f: f32, n: f32) -> f32 {
119         libm::powf(f, n)
120     }
121 
122     #[inline(always)]
mul_add(a: f32, b: f32, c: f32) -> f32123     pub(crate) fn mul_add(a: f32, b: f32, c: f32) -> f32 {
124         libm::fmaf(a, b, c)
125     }
126 
127     #[inline]
div_euclid(a: f32, b: f32) -> f32128     pub fn div_euclid(a: f32, b: f32) -> f32 {
129         // Based on https://doc.rust-lang.org/src/std/f32.rs.html#293
130         let q = libm::truncf(a / b);
131         if a % b < 0.0 {
132             return if b > 0.0 { q - 1.0 } else { q + 1.0 };
133         }
134         q
135     }
136 
137     #[inline]
rem_euclid(a: f32, b: f32) -> f32138     pub fn rem_euclid(a: f32, b: f32) -> f32 {
139         let r = a % b;
140         if r < 0.0 {
141             r + abs(b)
142         } else {
143             r
144         }
145     }
146 }
147 
148 #[cfg(not(feature = "libm"))]
149 mod std_math {
150     #[inline(always)]
abs(f: f32) -> f32151     pub(crate) fn abs(f: f32) -> f32 {
152         f32::abs(f)
153     }
154 
155     #[inline(always)]
acos_approx(f: f32) -> f32156     pub(crate) fn acos_approx(f: f32) -> f32 {
157         super::acos_approx_f32(f)
158     }
159 
160     #[inline(always)]
asin(f: f32) -> f32161     pub(crate) fn asin(f: f32) -> f32 {
162         f32::asin(f)
163     }
164 
165     #[inline(always)]
atan2(f: f32, other: f32) -> f32166     pub(crate) fn atan2(f: f32, other: f32) -> f32 {
167         f32::atan2(f, other)
168     }
169 
170     #[allow(unused)]
171     #[inline(always)]
sin(f: f32) -> f32172     pub(crate) fn sin(f: f32) -> f32 {
173         f32::sin(f)
174     }
175 
176     #[inline(always)]
sin_cos(f: f32) -> (f32, f32)177     pub(crate) fn sin_cos(f: f32) -> (f32, f32) {
178         f32::sin_cos(f)
179     }
180 
181     #[inline(always)]
tan(f: f32) -> f32182     pub(crate) fn tan(f: f32) -> f32 {
183         f32::tan(f)
184     }
185 
186     #[inline(always)]
sqrt(f: f32) -> f32187     pub(crate) fn sqrt(f: f32) -> f32 {
188         f32::sqrt(f)
189     }
190 
191     #[inline(always)]
copysign(f: f32, sign: f32) -> f32192     pub(crate) fn copysign(f: f32, sign: f32) -> f32 {
193         f32::copysign(f, sign)
194     }
195 
196     #[inline(always)]
signum(f: f32) -> f32197     pub(crate) fn signum(f: f32) -> f32 {
198         f32::signum(f)
199     }
200 
201     #[inline(always)]
round(f: f32) -> f32202     pub(crate) fn round(f: f32) -> f32 {
203         f32::round(f)
204     }
205 
206     #[inline(always)]
trunc(f: f32) -> f32207     pub(crate) fn trunc(f: f32) -> f32 {
208         f32::trunc(f)
209     }
210 
211     #[inline(always)]
ceil(f: f32) -> f32212     pub(crate) fn ceil(f: f32) -> f32 {
213         f32::ceil(f)
214     }
215 
216     #[inline(always)]
floor(f: f32) -> f32217     pub(crate) fn floor(f: f32) -> f32 {
218         f32::floor(f)
219     }
220 
221     #[inline(always)]
exp(f: f32) -> f32222     pub(crate) fn exp(f: f32) -> f32 {
223         f32::exp(f)
224     }
225 
226     #[inline(always)]
powf(f: f32, n: f32) -> f32227     pub(crate) fn powf(f: f32, n: f32) -> f32 {
228         f32::powf(f, n)
229     }
230 
231     #[inline(always)]
mul_add(a: f32, b: f32, c: f32) -> f32232     pub(crate) fn mul_add(a: f32, b: f32, c: f32) -> f32 {
233         f32::mul_add(a, b, c)
234     }
235 
236     #[inline]
div_euclid(a: f32, b: f32) -> f32237     pub fn div_euclid(a: f32, b: f32) -> f32 {
238         f32::div_euclid(a, b)
239     }
240 
241     #[inline]
rem_euclid(a: f32, b: f32) -> f32242     pub fn rem_euclid(a: f32, b: f32) -> f32 {
243         f32::rem_euclid(a, b)
244     }
245 }
246 
247 #[cfg(feature = "libm")]
248 pub(crate) use libm_math::*;
249 
250 #[cfg(not(feature = "libm"))]
251 pub(crate) use std_math::*;
252