use dsp_process::Process;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
pub struct Dsm<const K: usize> {
a: [u32; K],
c: [i8; K],
}
impl<const K: usize> Default for Dsm<K> {
fn default() -> Self {
const { assert!(K <= 8, "DSM order must be at most eight") }
Self {
a: [0; K],
c: [0; K],
}
}
}
impl<const K: usize> Process<u32, i8> for Dsm<K> {
fn process(&mut self, x: u32) -> i8 {
if K == 0 {
return 0;
}
let mut d = 0i8;
let mut c = false;
self.a.iter_mut().fold(x, |x, a| {
(*a, c) = a.overflowing_add(x);
d = (d << 1) | c as i8;
*a
});
self.c.iter_mut().take(K - 1).fold(d & 1, |mut y, c| {
d >>= 1;
(y, *c) = ((d & 1) + y - *c, y);
y
})
}
}
#[cfg(test)]
mod tests {
use super::*;
fn check<const K: usize>() {
for input in [0, 1, 0x1234_5678, 0x8000_0000, u32::MAX] {
let mut dsm = Dsm::<K>::default();
let mut sum = 0i64;
for _ in 0..65536 {
let y = dsm.process(input) as i64;
if K == 0 {
assert_eq!(y, 0);
} else {
assert!((1 - (1 << (K - 1))..=1 << (K - 1)).contains(&y));
}
sum += y;
}
if K > 0 {
assert!((sum as f64 / 65536.0 - input as f64 / 4294967296.0).abs() < 0.002);
}
}
}
#[test]
fn order_boundaries() {
check::<0>();
check::<1>();
check::<8>();
}
}