1#![no_std]
8
9pub type Angle = u16; pub type Fixed = i16; #[cfg(feature = "lut")]
25mod lut_impl {
26 use super::{Angle, Fixed};
27 const QUADRANT_BITS: u32 = 14;
28 const LUT_SIZE: usize = 256;
29 const LUT_BITS: u32 = 8;
30 const LUT_MASK: u32 = (1 << (QUADRANT_BITS - LUT_BITS)) - 1;
31
32 static SIN_LUT: [Fixed; 257] = include!("sin_table.rs.inc");
34
35 #[inline(always)]
36 pub fn sin_fixed(angle: Angle) -> Fixed {
37 let quadrant = (angle >> QUADRANT_BITS) as usize;
38 let idx = (angle & 0x3FFF) as u32;
39 let lut_idx = (idx >> (QUADRANT_BITS - LUT_BITS)) as usize;
40 let frac = (idx & LUT_MASK) as i32;
41
42 match quadrant {
43 0 => interpolate(SIN_LUT[lut_idx], SIN_LUT[lut_idx + 1], frac),
44 1 => interpolate(SIN_LUT[LUT_SIZE - lut_idx], SIN_LUT[LUT_SIZE - lut_idx - 1], frac),
45 2 => -interpolate(SIN_LUT[lut_idx], SIN_LUT[lut_idx + 1], frac),
46 _ => -interpolate(SIN_LUT[LUT_SIZE - lut_idx], SIN_LUT[LUT_SIZE - lut_idx - 1], frac),
47 }
48 }
49
50 #[inline(always)]
51 fn interpolate(y0: Fixed, y1: Fixed, frac: i32) -> Fixed {
52 let y0_32 = y0 as i32;
53 let y1_32 = y1 as i32;
54 (y0_32 + (((y1_32 - y0_32) * frac) >> (QUADRANT_BITS - LUT_BITS))) as Fixed
55 }
56}
57
58#[cfg(feature = "lut")]
60pub use lut_impl::sin_fixed;
61
62#[cfg(feature = "lut")]
63#[inline(always)]
64pub fn cos(angle: Angle) -> Fixed {
65 sin_fixed(angle.wrapping_add(16384))
66}
67
68#[cfg(feature = "lut")]
69#[inline(always)]
70pub fn sin_cos(angle: Angle) -> (Fixed, Fixed) {
71 (sin_fixed(angle), cos(angle))
72}
73
74#[cfg(feature = "taylor")]
78pub mod taylor_impl {
79 pub fn sin_taylor(x: f32) -> f32 {
80 let x2 = x * x;
81 x * (1.0 + x2 * (-0.166666666 + x2 * (0.008333333 + x2 * (-0.000198412 + x2 * 0.000002755))))
83 }
84}
85
86#[cfg(feature = "fast-sin")]
90pub mod fast_impl {
91 use core::f32::consts::PI;
92 pub fn sin_fast(x: f32) -> f32 {
93 let num = 16.0 * x * (PI - x.abs());
94 let den = 5.0 * PI * PI - 4.0 * x * (PI - x.abs());
95 num / den
96 }
97}
98
99#[inline(always)]
104pub fn to_fixed(x: f32) -> Fixed { (x * 32767.0) as Fixed }
105
106#[inline(always)]
107pub fn from_fixed(x: Fixed) -> f32 { (x as f32) / 32767.0 }
108
109#[inline(always)]
110pub fn radians_to_angle(rads: f32) -> Angle {
111 let scale = 65536.0 / (2.0 * core::f32::consts::PI);
112 (rads * scale) as i32 as u16
113}
114
115#[cfg(test)]
119mod tests {
120 extern crate std;
121 use super::*;
122 use core::f32::consts::PI;
123
124 #[cfg(feature = "lut")]
125 #[test]
126 fn test_sin_fixed_precision() {
127 assert!((sin_fixed(0) - 0).abs() <= 1);
129 assert!((sin_fixed(16384) - 32767).abs() <= 1); assert!((sin_fixed(32768) - 0).abs() <= 1); assert!((sin_fixed(49152) - (-32767)).abs() <= 1); let res_raw = sin_fixed(8192);
136 let expected_raw = 23203;
137
138 assert_eq!(res_raw, expected_raw, "Erreur de précision à 45°");
139 }
140
141 #[cfg(feature = "lut")]
142 #[test]
143 fn test_cos_fixed() {
144 assert!((cos(0) - 32767).abs() <= 1);
145 assert!(cos(16384).abs() <= 1);
146 assert!((cos(32768) - (-32767)).abs() <= 1);
147 }
148
149 #[cfg(feature = "taylor")]
150 #[test]
151 fn test_taylor_accuracy() {
152 let test_val = PI / 4.0;
153 let res = taylor_impl::sin_taylor(test_val);
154 let expected = test_val.sin();
155 assert!((res - expected).abs() < 0.0001);
156 }
157
158 #[cfg(feature = "fast-sin")]
159 #[test]
160 fn test_fast_sin_approximation() {
161 let res = fast_impl::sin_fast(PI / 6.0);
162 assert!((res - 0.5).abs() < 0.005);
163 }
164
165 #[test]
166 fn test_radians_to_angle_wrapping() {
167 assert_eq!(radians_to_angle(0.0), 0);
168 assert_eq!(radians_to_angle(2.0 * PI), 0);
169 let a = radians_to_angle(-PI / 2.0);
171 assert!(a == 49152 || a == 49151);
172 }
173
174 #[test]
175 fn test_fixed_conversion_roundtrip() {
176 let original = 0.5f32;
177 let fixed = to_fixed(original);
178 let back = from_fixed(fixed);
179 assert!((original - back).abs() < 0.0001);
180 }
181
182 #[test]
183 fn test_sin_cos_simultaneous() {
184 #[cfg(feature = "lut")]
185 {
186 let (s, c) = sin_cos(0);
187 assert_eq!(s, 0);
188 assert_eq!(c, 32767);
189 }
190 }
191}