1//! Square root approximation function for a single-precision float.
2//!
3//! Method described at: <https://bits.stephan-brumme.com/squareRoot.html>
4
5use super::F32;
6
7impl 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)]
21pub(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