glam/f32/
math.rs

1/// Returns a very close approximation of `self.clamp(-1.0, 1.0).acos()`.
2#[inline]
3fn 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")]
36mod libm_math {
37    #[inline(always)]
38    pub(crate) fn abs(f: f32) -> f32 {
39        libm::fabsf(f)
40    }
41
42    #[inline(always)]
43    pub(crate) fn acos_approx(f: f32) -> f32 {
44        super::acos_approx_f32(f)
45    }
46
47    #[inline(always)]
48    pub(crate) fn asin(f: f32) -> f32 {
49        libm::asinf(f)
50    }
51
52    #[inline(always)]
53    pub(crate) fn atan2(f: f32, other: f32) -> f32 {
54        libm::atan2f(f, other)
55    }
56
57    #[allow(unused)]
58    #[inline(always)]
59    pub(crate) fn sin(f: f32) -> f32 {
60        libm::sinf(f)
61    }
62
63    #[inline(always)]
64    pub(crate) fn sin_cos(f: f32) -> (f32, f32) {
65        libm::sincosf(f)
66    }
67
68    #[inline(always)]
69    pub(crate) fn tan(f: f32) -> f32 {
70        libm::tanf(f)
71    }
72
73    #[inline(always)]
74    pub(crate) fn sqrt(f: f32) -> f32 {
75        libm::sqrtf(f)
76    }
77
78    #[inline(always)]
79    pub(crate) fn copysign(f: f32, sign: f32) -> f32 {
80        libm::copysignf(f, sign)
81    }
82
83    #[inline(always)]
84    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)]
93    pub(crate) fn round(f: f32) -> f32 {
94        libm::roundf(f)
95    }
96
97    #[inline(always)]
98    pub(crate) fn trunc(f: f32) -> f32 {
99        libm::truncf(f)
100    }
101
102    #[inline(always)]
103    pub(crate) fn ceil(f: f32) -> f32 {
104        libm::ceilf(f)
105    }
106
107    #[inline(always)]
108    pub(crate) fn floor(f: f32) -> f32 {
109        libm::floorf(f)
110    }
111
112    #[inline(always)]
113    pub(crate) fn exp(f: f32) -> f32 {
114        libm::expf(f)
115    }
116
117    #[inline(always)]
118    pub(crate) fn powf(f: f32, n: f32) -> f32 {
119        libm::powf(f, n)
120    }
121
122    #[inline(always)]
123    pub(crate) fn mul_add(a: f32, b: f32, c: f32) -> f32 {
124        libm::fmaf(a, b, c)
125    }
126
127    #[inline]
128    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]
138    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"))]
149mod std_math {
150    #[inline(always)]
151    pub(crate) fn abs(f: f32) -> f32 {
152        f32::abs(f)
153    }
154
155    #[inline(always)]
156    pub(crate) fn acos_approx(f: f32) -> f32 {
157        super::acos_approx_f32(f)
158    }
159
160    #[inline(always)]
161    pub(crate) fn asin(f: f32) -> f32 {
162        f32::asin(f)
163    }
164
165    #[inline(always)]
166    pub(crate) fn atan2(f: f32, other: f32) -> f32 {
167        f32::atan2(f, other)
168    }
169
170    #[allow(unused)]
171    #[inline(always)]
172    pub(crate) fn sin(f: f32) -> f32 {
173        f32::sin(f)
174    }
175
176    #[inline(always)]
177    pub(crate) fn sin_cos(f: f32) -> (f32, f32) {
178        f32::sin_cos(f)
179    }
180
181    #[inline(always)]
182    pub(crate) fn tan(f: f32) -> f32 {
183        f32::tan(f)
184    }
185
186    #[inline(always)]
187    pub(crate) fn sqrt(f: f32) -> f32 {
188        f32::sqrt(f)
189    }
190
191    #[inline(always)]
192    pub(crate) fn copysign(f: f32, sign: f32) -> f32 {
193        f32::copysign(f, sign)
194    }
195
196    #[inline(always)]
197    pub(crate) fn signum(f: f32) -> f32 {
198        f32::signum(f)
199    }
200
201    #[inline(always)]
202    pub(crate) fn round(f: f32) -> f32 {
203        f32::round(f)
204    }
205
206    #[inline(always)]
207    pub(crate) fn trunc(f: f32) -> f32 {
208        f32::trunc(f)
209    }
210
211    #[inline(always)]
212    pub(crate) fn ceil(f: f32) -> f32 {
213        f32::ceil(f)
214    }
215
216    #[inline(always)]
217    pub(crate) fn floor(f: f32) -> f32 {
218        f32::floor(f)
219    }
220
221    #[inline(always)]
222    pub(crate) fn exp(f: f32) -> f32 {
223        f32::exp(f)
224    }
225
226    #[inline(always)]
227    pub(crate) fn powf(f: f32, n: f32) -> f32 {
228        f32::powf(f, n)
229    }
230
231    #[inline(always)]
232    pub(crate) fn mul_add(a: f32, b: f32, c: f32) -> f32 {
233        f32::mul_add(a, b, c)
234    }
235
236    #[inline]
237    pub fn div_euclid(a: f32, b: f32) -> f32 {
238        f32::div_euclid(a, b)
239    }
240
241    #[inline]
242    pub fn rem_euclid(a: f32, b: f32) -> f32 {
243        f32::rem_euclid(a, b)
244    }
245}
246
247#[cfg(feature = "libm")]
248pub(crate) use libm_math::*;
249
250#[cfg(not(feature = "libm"))]
251pub(crate) use std_math::*;