use std::f32::consts::PI;
pub fn dct2(input: &[f32]) -> Vec<f32> {
let n = input.len();
let mut output = vec![0.0; n];
let mut table = vec![0.0; n];
for (k, out) in output.iter_mut().enumerate() {
for (t, slot) in table.iter_mut().enumerate() {
*slot = (PI / n as f32 * (t as f32 + 0.5) * k as f32).cos();
}
*out = crate::simd::dot(input, &table);
}
output
}
pub fn idct2(input: &[f32]) -> Vec<f32> {
let n = input.len();
if n == 0 {
return Vec::new();
}
let mut output = vec![0.0; n];
let mut table = vec![0.0; n];
for (t, out) in output.iter_mut().enumerate() {
table[0] = 0.5;
for (k, slot) in table.iter_mut().enumerate().skip(1) {
*slot = (PI / n as f32 * (t as f32 + 0.5) * k as f32).cos();
}
*out = crate::simd::dot(input, &table) * 2.0 / n as f32;
}
output
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn idct2_of_dct2_is_identity() {
let input: Vec<f32> = (0..40).map(|i| (i as f32 * 0.21).sin() + 0.3).collect();
let roundtrip = idct2(&dct2(&input));
for (a, b) in input.iter().zip(roundtrip.iter()) {
assert!((a - b).abs() < 1e-4, "{} vs {}", a, b);
}
}
}