#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub fn scale_copy_vector16(data_out: &mut [i16], data_in: &[i16], gain_q16: i32) {
assert_eq!(
data_out.len(),
data_in.len(),
"input and output slices must match in length"
);
for (dst, &src) in data_out.iter_mut().zip(data_in.iter()) {
let scaled = smulwb(gain_q16, i32::from(src));
*dst = cast_to_i16(scaled);
}
}
pub fn scale_vector32_q26_lshift_18(data: &mut [i32], gain_q26: i32) {
for value in data.iter_mut() {
let product = i64::from(*value) * i64::from(gain_q26);
let shifted = product >> 8;
*value = cast_to_i32(shifted);
}
}
pub fn inner_prod16(in_vec1: &[i16], in_vec2: &[i16]) -> i64 {
assert_eq!(
in_vec1.len(),
in_vec2.len(),
"input vectors must have identical lengths"
);
let mut sum = 0i64;
for (&a, &b) in in_vec1.iter().zip(in_vec2.iter()) {
sum = sum.wrapping_add(i64::from(a) * i64::from(b));
}
sum
}
#[inline]
fn smulwb(a: i32, b: i32) -> i32 {
((i64::from(a) * i64::from(b as i16)) >> 16) as i32
}
#[inline]
fn cast_to_i16(value: i32) -> i16 {
#[cfg(all(debug_assertions, feature = "silk_strict_asserts"))]
assert!(
(i32::from(i16::MIN)..=i32::from(i16::MAX)).contains(&value),
"value {value} cannot be represented as i16"
);
value as i16
}
#[inline]
fn cast_to_i32(value: i64) -> i32 {
#[cfg(all(debug_assertions, feature = "silk_strict_asserts"))]
assert!(
(i64::from(i32::MIN)..=i64::from(i32::MAX)).contains(&value),
"value {value} cannot be represented as i32"
);
value as i32
}
#[cfg(test)]
mod tests {
use super::{inner_prod16, scale_copy_vector16, scale_vector32_q26_lshift_18};
use alloc::vec::Vec;
#[test]
fn scale_copy_matches_reference() {
let input = [1234, -2345, 32767, -32768];
let gain_q16 = (3 * (1 << 16)) / 4; let mut output = [0i16; 4];
scale_copy_vector16(&mut output, &input, gain_q16);
let expected: Vec<i16> = input
.iter()
.map(|&x| ((i64::from(gain_q16) * i64::from(x)) >> 16) as i16)
.collect();
assert_eq!(output.as_slice(), expected.as_slice());
}
#[test]
fn scale_vector32_matches_reference() {
let gain_q26 = (1 << 26) / 4; let mut data = [1 << 12, -(1 << 11), 12345, -9876];
let expected: Vec<i32> = data
.iter()
.map(|&x| ((i64::from(x) * i64::from(gain_q26)) >> 8) as i32)
.collect();
scale_vector32_q26_lshift_18(&mut data, gain_q26);
assert_eq!(data.as_slice(), expected.as_slice());
}
#[test]
fn inner_product_matches_manual_sum() {
let a = [300, -400, 500, -600, 42];
let b = [-7, 9, -11, 13, -21];
let expected = a
.iter()
.zip(b.iter())
.map(|(&x, &y)| i64::from(x) * i64::from(y))
.sum::<i64>();
assert_eq!(inner_prod16(&a, &b), expected);
}
#[test]
fn inner_product_empty_slice_is_zero() {
let empty: [i16; 0] = [];
assert_eq!(inner_prod16(&empty, &empty), 0);
}
}