1use num_traits::PrimInt;
9
10pub trait FastInvSqrt {
12 fn fast_invsqrt(x: Self) -> Self;
17}
18
19impl FastInvSqrt for f32 {
20 #[inline]
21 fn fast_invsqrt(x: Self) -> Self {
22 fast_invsqrt_32(x)
23 }
24}
25
26impl FastInvSqrt for f64 {
27 #[inline]
28 fn fast_invsqrt(x: Self) -> Self {
29 fast_invsqrt_64(x)
30 }
31}
32
33pub fn fast_invsqrt_32(x: f32) -> f32 {
39 let approx = 0x5f375a86u32;
40 let xhalf = 0.5 * x;
41 let i = x.to_bits();
42 let i = approx - (i >> 1);
43 let y = f32::from_bits(i);
44 y * (1.5 - xhalf * y * y)
45}
46
47pub fn fast_invsqrt_64(x: f64) -> f64 {
53 let approx = 0x5fe6eb50c7aa19f9u64;
54 let xhalf = 0.5 * x;
55 let i = x.to_bits();
56 let i = approx - (i >> 1);
57 let y = f64::from_bits(i);
58 y * (1.5 - xhalf * y * y)
59}
60
61#[test]
62fn test_fast_invsqrt_32() {
63 for i in 1..1000000 {
64 let x = i as f32;
65 let inv_sqrt_approx = fast_invsqrt_32(x);
66 let inv_sqrt = 1. / x.sqrt();
67 let abs_diff = (inv_sqrt - inv_sqrt_approx).abs();
68 assert!(abs_diff / inv_sqrt < 0.002, "Error should be below 0.2%.")
69 }
70}
71
72#[test]
73fn test_fast_invsqrt_64() {
74 for i in 1..1000000 {
75 let x = i as f64;
76 let inv_sqrt_approx = fast_invsqrt_64(x);
77 let inv_sqrt = 1. / x.sqrt();
78 let abs_diff = (inv_sqrt - inv_sqrt_approx).abs();
79 assert!(abs_diff / inv_sqrt < 0.002, "Error should be below 0.2%.")
80 }
81}
82
83pub fn int_sqrt_floor<T: PrimInt>(n: T) -> T {
101 assert!(
102 n >= T::zero(),
103 "Cannot compute the square root of a negative number."
104 );
105 let one = T::one();
106 let two = one + one;
107 let mut x = n;
108 let mut y = (x + one) / two;
109 while y < x {
110 x = y;
111 y = (x + (n / x)) / two;
112 }
113 x
114}
115
116#[test]
117pub fn test_int_sqrt_floor_i32() {
118 for i in 0..100000i32 {
119 let sqrt = int_sqrt_floor(i);
120 let sqrt_reference = (i as f64).sqrt().floor() as i32;
121 assert_eq!(sqrt, sqrt_reference);
122
123 let i_lower = sqrt * sqrt;
124 let i_upper = (sqrt + 1) * (sqrt + 1);
125 assert!(i_lower <= i && i < i_upper);
126 }
127}