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