use crate::math::{clip3, round2};
pub(crate) const COS128_LOOKUP: [i64; 65] = [
4096, 4095, 4091, 4085, 4076, 4065, 4052, 4036, 4017, 3996, 3973, 3948, 3920, 3889, 3857, 3822,
3784, 3745, 3703, 3659, 3612, 3564, 3513, 3461, 3406, 3349, 3290, 3229, 3166, 3102, 3035, 2967,
2896, 2824, 2751, 2675, 2598, 2520, 2440, 2359, 2276, 2191, 2106, 2019, 1931, 1842, 1751, 1660,
1567, 1474, 1380, 1285, 1189, 1092, 995, 897, 799, 700, 601, 501, 401, 301, 201, 101, 0,
];
pub(crate) fn cos128(angle: i32) -> i64 {
let angle2 = angle & 255;
if angle2 <= 64 {
COS128_LOOKUP[angle2 as usize]
} else if angle2 <= 128 {
-COS128_LOOKUP[(128 - angle2) as usize]
} else if angle2 <= 192 {
-COS128_LOOKUP[(angle2 - 128) as usize]
} else {
COS128_LOOKUP[(256 - angle2) as usize]
}
}
pub(crate) fn sin128(angle: i32) -> i64 {
cos128(angle - 64)
}
pub(crate) fn brev(num_bits: u32, x: i32) -> i32 {
let mut t = 0;
for i in 0..num_bits {
let bit = (x >> i) & 1;
t += bit << (num_bits - 1 - i);
}
t
}
pub(crate) fn b(t: &mut [i64], a: i32, bb: i32, angle: i32, flip: bool, _r: u32) {
let (a, bb) = (a as usize, bb as usize);
let cos = cos128(angle);
let sin = sin128(angle);
let x = t[a] * cos - t[bb] * sin;
let y = t[a] * sin + t[bb] * cos;
t[a] = round2(x, 12);
t[bb] = round2(y, 12);
if flip {
t.swap(a, bb);
}
}
pub(crate) fn h(t: &mut [i64], a: i32, bb: i32, flip: bool, r: u32) {
if flip {
h(t, bb, a, false, r);
return;
}
let (a, bb) = (a as usize, bb as usize);
let lim = 1i64 << (r - 1);
let x = t[a];
let y = t[bb];
t[a] = clip3(-lim, lim - 1, x + y);
t[bb] = clip3(-lim, lim - 1, x - y);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cos128_matches_float_reference() {
for angle in -300..=300 {
let want = (4096.0 * (f64::from(angle) * std::f64::consts::PI / 128.0).cos()).round();
assert_eq!(cos128(angle), want as i64, "cos128({angle})");
}
}
#[test]
fn sin128_is_cos_shifted() {
for angle in -300..=300 {
let want = (4096.0 * (f64::from(angle) * std::f64::consts::PI / 128.0).sin()).round();
assert_eq!(sin128(angle), want as i64, "sin128({angle})");
}
}
#[test]
fn brev_reverses_bits() {
assert_eq!(brev(4, 0b0001), 0b1000);
assert_eq!(brev(4, 0b0110), 0b0110);
assert_eq!(brev(3, 0b001), 0b100);
assert_eq!(brev(4, 0b1011), 0b1101);
}
#[test]
fn hadamard_is_sum_and_difference() {
let mut t = [5i64, 3];
h(&mut t, 0, 1, false, 16);
assert_eq!(t, [8, 2]);
let mut t = [5i64, 3];
h(&mut t, 0, 1, true, 16);
assert_eq!(t, [-2, 8]);
}
}