1 | //! Square root approximation function for a single-precision float. |
2 | //! |
3 | //! Method described at: <https://bits.stephan-brumme.com/squareRoot.html> |
4 | |
5 | use super::F32; |
6 | |
7 | impl F32 { |
8 | /// Approximates the square root of a number with an average deviation of ~5%. |
9 | /// |
10 | /// Returns [`Self::NAN`] if `self` is a negative number. |
11 | pub fn sqrt(self) -> Self { |
12 | if self >= Self::ZERO { |
13 | Self::from_bits((self.to_bits() + 0x3f80_0000) >> 1) |
14 | } else { |
15 | Self::NAN |
16 | } |
17 | } |
18 | } |
19 | |
20 | #[cfg (test)] |
21 | pub(crate) mod tests { |
22 | use super::F32; |
23 | |
24 | /// Deviation from the actual value (5%) |
25 | pub(crate) const MAX_ERROR: f32 = 0.05; |
26 | |
27 | /// Square root test vectors - `(input, output)` |
28 | pub(crate) const TEST_VECTORS: &[(f32, f32)] = &[ |
29 | (1.0, 1.0), |
30 | (2.0, 1.414), |
31 | (3.0, 1.732), |
32 | (4.0, 2.0), |
33 | (5.0, 2.236), |
34 | (10.0, 3.162), |
35 | (100.0, 10.0), |
36 | (250.0, 15.811), |
37 | (500.0, 22.36), |
38 | (1000.0, 31.622), |
39 | (2500.0, 50.0), |
40 | (5000.0, 70.710), |
41 | (1000000.0, 1000.0), |
42 | (2500000.0, 1581.138), |
43 | (5000000.0, 2236.067), |
44 | (10000000.0, 3162.277), |
45 | (25000000.0, 5000.0), |
46 | (50000000.0, 7071.067), |
47 | (100000000.0, 10000.0), |
48 | ]; |
49 | |
50 | #[test ] |
51 | fn sanity_check() { |
52 | for &(x, expected) in TEST_VECTORS { |
53 | let sqrt_x = F32(x).sqrt(); |
54 | let allowed_delta = x * MAX_ERROR; |
55 | let actual_delta = sqrt_x - expected; |
56 | |
57 | assert!( |
58 | actual_delta <= allowed_delta, |
59 | "delta {} too large: {} vs {}" , |
60 | actual_delta, |
61 | sqrt_x, |
62 | expected |
63 | ); |
64 | } |
65 | } |
66 | |
67 | #[test ] |
68 | fn negative_is_nan() { |
69 | assert!(F32(-1.0).sqrt().is_nan()); |
70 | } |
71 | } |
72 | |