1use crate::common::error::{Error, Result};
2use crate::common::tables::{SQRT_INITIAL_LUT_U16, SQRT_INITIAL_LUT_U32};
3
4#[inline]
5fn sqrt_newton_q15(number: i32, mut var1: i32) -> i32 {
6 for _ in 0..3 {
7 let mut temp = (var1 * var1) >> 12;
8 temp = (number * temp) >> 15;
9 temp = 0x3000 - temp;
10 var1 = (var1 * temp) >> 13;
11 }
12
13 (number * var1) >> 12
14}
15
16#[inline]
17fn sqrt_newton_q31(number: i64, mut var1: i64) -> i64 {
18 for _ in 0..3 {
19 let mut temp = (var1 * var1) >> 28;
20 temp = (number * temp) >> 31;
21 temp = 0x30000000 - temp;
22 var1 = (var1 * temp) >> 29;
23 }
24
25 (number * var1) >> 28
26}
27
28pub fn sqrt_i16(input: i16) -> Result<i16> {
30 if input < 0 {
31 return Err(Error::NanInf);
32 }
33
34 if input == 0 {
35 return Ok(0);
36 }
37
38 let input_u = input as u16 as u32;
39 let sign_bits = input_u.leading_zeros() as i32 - 17;
40 let shift = if sign_bits & 1 == 0 {
41 sign_bits
42 } else {
43 sign_bits - 1
44 } as u32;
45
46 let number = (input as i32).wrapping_shl(shift);
47 let index = (((number >> 11) as usize) - (0x2000usize >> 11)) as usize;
48 let var1 = SQRT_INITIAL_LUT_U16[index] as i32;
49 let mut result = sqrt_newton_q15(number, var1);
50
51 let final_shift = if sign_bits & 1 == 0 {
52 (sign_bits / 2) as u32
53 } else {
54 ((sign_bits - 1) / 2) as u32
55 };
56 result >>= final_shift;
57
58 Ok(result as i16)
59}
60
61pub fn sqrt_i32(input: i32) -> Result<i32> {
63 if input < 0 {
64 return Err(Error::NanInf);
65 }
66
67 if input == 0 {
68 return Ok(0);
69 }
70
71 let input_u = input as u32;
72 let sign_bits = input_u.leading_zeros() as i32 - 1;
73 let shift = if sign_bits & 1 == 0 {
74 sign_bits
75 } else {
76 sign_bits - 1
77 } as u32;
78
79 let number = (input as i64).wrapping_shl(shift);
80 let index = (((number >> 26) as usize) - (0x20000000usize >> 26)) as usize;
81 let var1 = SQRT_INITIAL_LUT_U32[index] as i64;
82 let mut result = sqrt_newton_q31(number, var1);
83
84 let final_shift = if sign_bits & 1 == 0 {
85 (sign_bits / 2) as u32
86 } else {
87 ((sign_bits - 1) / 2) as u32
88 };
89 result >>= final_shift;
90
91 Ok(result as i32)
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn sqrt_q15_handles_sign_and_zero() {
100 assert_eq!(sqrt_i16(-1), Err(Error::NanInf));
101 assert_eq!(sqrt_i16(0), Ok(0));
102 }
103
104 #[test]
105 fn sqrt_q31_handles_sign_and_zero() {
106 assert_eq!(sqrt_i32(-1), Err(Error::NanInf));
107 assert_eq!(sqrt_i32(0), Ok(0));
108 }
109}