use core::f32::consts::PI;
const SIN_TABLE: [i16; 256] = generate_sin_table();
const fn generate_sin_table() -> [i16; 256] {
let mut table = [0i16; 256];
let mut i = 0;
while i < 256 {
let angle_rad = (i as f32 * 2.0 * PI) / 256.0;
let x = angle_rad;
let x2 = x * x;
let x3 = x2 * x;
let x5 = x3 * x2;
let x7 = x5 * x2;
let x9 = x7 * x2;
let x11 = x9 * x2;
let sin_val = x
- x3 / 6.0 + x5 / 120.0 - x7 / 5040.0 + x9 / 362880.0 - x11 / 39916800.0;
table[i] = (sin_val * 32768.0) as i16;
i += 1;
}
table
}
#[inline(always)]
pub fn fast_sin_i16(angle: f32) -> i16 {
let normalized = (angle % (2.0 * PI)) / (2.0 * PI);
let index = ((normalized * 256.0) as usize) & 0xFF;
SIN_TABLE[index]
}
#[inline(always)]
pub fn fast_cos_i16(angle: f32) -> i16 {
fast_sin_i16(angle + PI / 2.0)
}
#[inline(always)]
pub fn fast_sin(angle: f32) -> f32 {
fast_sin_i16(angle) as f32 / 32768.0
}
#[inline(always)]
pub fn fast_cos(angle: f32) -> f32 {
fast_cos_i16(angle) as f32 / 32768.0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sin_accuracy() {
extern crate std;
let test_angles = [
0.0,
PI / 6.0,
PI / 4.0,
PI / 3.0,
PI / 2.0,
PI,
3.0 * PI / 2.0,
];
for angle in test_angles.iter() {
let fast = fast_sin(*angle);
let accurate = angle.sin();
let error = (fast - accurate).abs();
std::println!(
"sin({:.3}): fast={:.4}, accurate={:.4}, error={:.4}",
angle,
fast,
accurate,
error
);
assert!(
error < 0.02,
"Error too large at angle {}: {}",
angle,
error
);
}
}
#[test]
fn test_cos_accuracy() {
extern crate std;
let test_angles = [0.0, PI / 6.0, PI / 4.0, PI / 3.0, PI / 2.0, PI];
for angle in test_angles.iter() {
let fast = fast_cos(*angle);
let accurate = angle.cos();
let error = (fast - accurate).abs();
std::println!(
"cos({:.3}): fast={:.4}, accurate={:.4}, error={:.4}",
angle,
fast,
accurate,
error
);
assert!(
error < 0.02,
"Error too large at angle {}: {}",
angle,
error
);
}
}
#[test]
fn test_periodicity() {
extern crate std;
let angle = PI / 4.0;
let sin1 = fast_sin(angle);
let sin2 = fast_sin(angle + 2.0 * PI);
let sin3 = fast_sin(angle + 4.0 * PI);
std::println!(
"Periodicity test: sin1={:.4}, sin2={:.4}, sin3={:.4}",
sin1,
sin2,
sin3
);
std::println!(
"Differences: |sin1-sin2|={:.4}, |sin1-sin3|={:.4}",
(sin1 - sin2).abs(),
(sin1 - sin3).abs()
);
assert!(
(sin1 - sin2).abs() < 0.02,
"Periodicity error too large: {}",
(sin1 - sin2).abs()
);
assert!(
(sin1 - sin3).abs() < 0.02,
"Periodicity error too large: {}",
(sin1 - sin3).abs()
);
}
}