• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[cfg(feature = "libm")]
2 #[allow(unused_imports)]
3 use num_traits::Float;
4 
5 pub(crate) trait FloatEx {
6     /// Returns a very close approximation of `self.clamp(-1.0, 1.0).acos()`.
acos_approx(self) -> Self7     fn acos_approx(self) -> Self;
8 }
9 
10 impl FloatEx for f32 {
11     #[inline(always)]
acos_approx(self) -> Self12     fn acos_approx(self) -> Self {
13         // Based on https://github.com/microsoft/DirectXMath `XMScalarAcos`
14         // Clamp input to [-1,1].
15         let nonnegative = self >= 0.0;
16         let x = self.abs();
17         let mut omx = 1.0 - x;
18         if omx < 0.0 {
19             omx = 0.0;
20         }
21         let root = omx.sqrt();
22 
23         // 7-degree minimax approximation
24         #[allow(clippy::approx_constant)]
25         let mut result = ((((((-0.001_262_491_1 * x + 0.006_670_09) * x - 0.017_088_126) * x
26             + 0.030_891_88)
27             * x
28             - 0.050_174_303)
29             * x
30             + 0.088_978_99)
31             * x
32             - 0.214_598_8)
33             * x
34             + 1.570_796_3;
35         result *= root;
36 
37         // acos(x) = pi - acos(-x) when x < 0
38         if nonnegative {
39             result
40         } else {
41             core::f32::consts::PI - result
42         }
43     }
44 }
45 
46 impl FloatEx for f64 {
47     #[inline(always)]
acos_approx(self) -> Self48     fn acos_approx(self) -> Self {
49         f64::acos(self.clamp(-1.0, 1.0))
50     }
51 }
52