Skip to main content

fixed_dsp/basic/
dot.rs

1/// Dot product of two Q15 vectors.
2///
3/// Each multiplication is in 2.30 format and accumulated into a 64-bit sum.
4/// The returned value matches CMSIS 34.30 accumulator semantics.
5pub fn dot_i16(a: &[i16], b: &[i16]) -> i64 {
6    assert_eq!(a.len(), b.len(), "input slices must have the same length");
7
8    let mut sum: i64 = 0;
9    for (&x, &y) in a.iter().zip(b.iter()) {
10        sum = sum.wrapping_add((x as i32 as i64) * (y as i32 as i64));
11    }
12
13    sum
14}
15
16/// Dot product of two Q31 vectors.
17///
18/// CMSIS truncates each 2.62 product to 2.48 by discarding 14 LSBs,
19/// then accumulates into a 64-bit 16.48 accumulator.
20pub fn dot_i32(a: &[i32], b: &[i32]) -> i64 {
21    assert_eq!(a.len(), b.len(), "input slices must have the same length");
22
23    let mut sum: i64 = 0;
24    for (&x, &y) in a.iter().zip(b.iter()) {
25        let prod = ((x as i64) * (y as i64)) >> 14;
26        sum = sum.wrapping_add(prod);
27    }
28
29    sum
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    #[test]
37    fn dot_i16_basic() {
38        let a = [0x4000_i16, 0x4000_i16]; // 0.5, 0.5
39        let b = [0x4000_i16, 0x2000_i16]; // 0.5, 0.25
40
41        let out = dot_i16(&a, &b);
42        assert_eq!(out, 402_653_184);
43    }
44
45    #[test]
46    fn dot_i32_basic() {
47        let a = [0x4000_0000_i32, 0x4000_0000_i32];
48        let b = [0x4000_0000_i32, 0x2000_0000_i32];
49
50        let out = dot_i32(&a, &b);
51        let expected = (((0x4000_0000_i64 * 0x4000_0000_i64) >> 14)
52            + ((0x4000_0000_i64 * 0x2000_0000_i64) >> 14)) as i64;
53        assert_eq!(out, expected);
54    }
55}