#![no_std]
pub type Angle = u16; pub type Fixed = i16;
#[cfg(feature = "lut")]
mod lut_impl {
use super::{Angle, Fixed};
const QUADRANT_BITS: u32 = 14;
const LUT_SIZE: usize = 256;
const LUT_BITS: u32 = 8;
const LUT_MASK: u32 = (1 << (QUADRANT_BITS - LUT_BITS)) - 1;
static SIN_LUT: [Fixed; 257] = include!("sin_table.rs.inc");
#[inline(always)]
pub fn sin_fixed(angle: Angle) -> Fixed {
let quadrant = (angle >> QUADRANT_BITS) as usize;
let idx = (angle & 0x3FFF) as u32;
let lut_idx = (idx >> (QUADRANT_BITS - LUT_BITS)) as usize;
let frac = (idx & LUT_MASK) as i32;
match quadrant {
0 => interpolate(SIN_LUT[lut_idx], SIN_LUT[lut_idx + 1], frac),
1 => interpolate(SIN_LUT[LUT_SIZE - lut_idx], SIN_LUT[LUT_SIZE - lut_idx - 1], frac),
2 => -interpolate(SIN_LUT[lut_idx], SIN_LUT[lut_idx + 1], frac),
_ => -interpolate(SIN_LUT[LUT_SIZE - lut_idx], SIN_LUT[LUT_SIZE - lut_idx - 1], frac),
}
}
#[inline(always)]
fn interpolate(y0: Fixed, y1: Fixed, frac: i32) -> Fixed {
let y0_32 = y0 as i32;
let y1_32 = y1 as i32;
(y0_32 + (((y1_32 - y0_32) * frac) >> (QUADRANT_BITS - LUT_BITS))) as Fixed
}
}
#[cfg(feature = "lut")]
pub use lut_impl::sin_fixed;
#[cfg(feature = "lut")]
#[inline(always)]
pub fn cos(angle: Angle) -> Fixed {
sin_fixed(angle.wrapping_add(16384))
}
#[cfg(feature = "lut")]
#[inline(always)]
pub fn sin_cos(angle: Angle) -> (Fixed, Fixed) {
(sin_fixed(angle), cos(angle))
}
#[cfg(feature = "taylor")]
pub mod taylor_impl {
use super::{Angle, Fixed};
pub fn sin_taylor(angle: Angle) -> Fixed {
let x_input = if angle > 32768 { 65536 - angle as i32 } else { angle as i32 };
let x = if x_input > 16384 { 32768 - x_input } else { x_input };
let x_rad = (x * 51472) >> 14;
let x2 = (x_rad * x_rad) >> 15;
let x3 = (x2 * x_rad) >> 15;
let x5 = (((x3 * x2) >> 15) * x2) >> 15;
let term3 = (x3 * 5461) >> 15;
let term5 = (x5 * 273) >> 15;
let res = (x_rad - term3 + term5) as Fixed;
if angle > 32768 { -res } else { res }
}
}
#[cfg(feature = "fast-sin")]
pub mod fast_impl {
use super::{Angle, Fixed};
pub fn sin_fast(angle: Angle) -> Fixed {
let x = (angle & 0x7FFF) as i32;
let pi = 32768i32;
let x_pi_x = (x * (pi - x)) >> 15;
let num = (x_pi_x as i64) * 16;
let den = (5 * 32768) - ((4 * x_pi_x) >> 0);
let res = (num * 32767) / den as i64;
let val = res as Fixed;
if angle > 32768 { -val } else { val }
}
}
#[inline(always)]
pub fn to_fixed(x: f32) -> Fixed { (x * 32767.0) as Fixed }
#[inline(always)]
pub fn from_fixed(x: Fixed) -> f32 { (x as f32) / 32767.0 }
#[inline(always)]
pub fn radians_to_angle(rads: f32) -> Angle {
let scale = 65536.0 / (2.0 * core::f32::consts::PI);
(rads * scale) as i32 as u16
}
#[cfg(test)]
mod tests {
extern crate std;
use super::*;
use core::f32::consts::PI;
#[cfg(feature = "lut")]
#[test]
fn test_sin_fixed_precision() {
assert!((sin_fixed(0) - 0).abs() <= 1);
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);
let expected_raw = 23203;
assert_eq!(res_raw, expected_raw, "Erreur de précision à 45°");
}
#[cfg(feature = "lut")]
#[test]
fn test_cos_fixed() {
assert!((cos(0) - 32767).abs() <= 1);
assert!(cos(16384).abs() <= 1);
assert!((cos(32768) - (-32767)).abs() <= 1);
}
#[cfg(feature = "taylor")]
#[test]
fn test_taylor_accuracy() {
let res = taylor_impl::sin_taylor(8192); let expected = 23170;
assert!((res - expected).abs() < 1000); }
#[cfg(feature = "fast-sin")]
#[test]
fn test_fast_sin_approximation() {
let res = fast_impl::sin_fast(5461);
let expected = 16384;
assert!((res - expected).abs() < 1500, "Valeur reçue: {}", res);
}
#[test]
fn test_radians_to_angle_wrapping() {
assert_eq!(radians_to_angle(0.0), 0);
assert_eq!(radians_to_angle(2.0 * PI), 0);
let a = radians_to_angle(-PI / 2.0);
assert!(a == 49152 || a == 49151);
}
#[test]
fn test_fixed_conversion_roundtrip() {
let original = 0.5f32;
let fixed = to_fixed(original);
let back = from_fixed(fixed);
assert!((original - back).abs() < 0.0001);
}
#[test]
fn test_sin_cos_simultaneous() {
#[cfg(feature = "lut")]
{
let (s, c) = sin_cos(0);
assert_eq!(s, 0);
assert_eq!(c, 32767);
}
}
}