1//! Takes the reciprocal (inverse) of a number, `1/x`.
2
3use super::F32;
4
5impl F32 {
6 /// Returns the reciprocal (inverse) of a number, `1/x`.
7 pub fn recip(self) -> Self {
8 let mut x: F32 = self;
9
10 let sx: F32 = if x < 0.0 { F32(-1.0) } else { F32(1.0) };
11 x *= sx;
12
13 let mut v: F32 = F32(f32::from_bits(0x7EF1_27EAu32.wrapping_sub(x.to_bits())));
14 let w: F32 = x * v;
15
16 // v.0 *= 2.0 - w;
17 // v.0 *= 4.0 + w * (-6.0 + w * (4.0 - w));
18 v.0 *=
19 8.0 + w * (-28.0 + w * (56.0 + w * (-70.0 + w * (56.0 + w * (-28.0 + w * (8.0 - w))))));
20
21 v.0 * sx
22 }
23}
24
25#[cfg(test)]
26mod tests {
27 use super::F32;
28
29 pub(crate) const MAX_ERROR: f32 = 1e-5;
30
31 pub(crate) const TEST_VECTORS: &[(f32, f32)] = &[
32 (0.00001, 100000.0),
33 (1.0, 1.0),
34 (2.0, 0.5),
35 (0.25, 4.0),
36 (-0.5, -2.0),
37 (core::f32::consts::PI, 1.0 / core::f32::consts::PI),
38 ];
39
40 #[test]
41 fn sanity_check() {
42 assert_eq!(F32(0.0).recip(), F32(core::f32::INFINITY));
43 assert_eq!(F32(-0.0).recip(), F32(core::f32::NEG_INFINITY));
44
45 for &(x, expected) in TEST_VECTORS {
46 let recip_x = F32(x).recip();
47 let relative_error = (recip_x - expected).abs() / expected;
48
49 assert!(
50 relative_error <= MAX_ERROR,
51 "relative_error {} too large for input {} : {} vs {}",
52 relative_error,
53 x,
54 recip_x,
55 expected
56 );
57 }
58 }
59}
60