#![no_std]
#![forbid(unsafe_code)]
const LN2_Q15: i32 = 22713;
const INV_LN2_Q15: i32 = 47274;
const INV_6_Q15: i32 = 5461; const INV_24_Q15: i32 = 1365;
#[inline]
pub fn exp_q15(x: i16) -> i16 {
if x >= 0 {
return i16::MAX;
}
let x_i32 = x as i32;
let n: i32 = (x_i32 * INV_LN2_Q15) >> 30;
let r: i32 = x_i32 - n * LN2_Q15;
let r2: i32 = (r * r) >> 15;
let r3: i32 = (r2 * r) >> 15;
let r4: i32 = (r3 * r) >> 15;
let er: i32 = 32768 + r + (r2 >> 1) + ((r3 * INV_6_Q15) >> 15) + ((r4 * INV_24_Q15) >> 15);
let result: i32 = er >> (-n);
if result >= 32767 {
32767
} else if result <= 0 {
0
} else {
result as i16
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_exp_zero_saturates() {
assert_eq!(exp_q15(0), i16::MAX);
}
#[test]
fn test_exp_saturation_positive() {
assert_eq!(exp_q15(1), i16::MAX);
assert_eq!(exp_q15(i16::MAX), i16::MAX);
}
#[test]
fn test_exp_negative_eighth() {
let res = exp_q15(-4096);
assert!((res as i32 - 28917).abs() < 10, "exp(-0.125): attendu ≈28917, reçu {}", res);
}
#[test]
fn test_exp_negative_quarter() {
let res = exp_q15(-8192);
assert!((res as i32 - 25519).abs() < 10, "exp(-0.25): attendu ≈25519, reçu {}", res);
}
#[test]
fn test_exp_negative_half() {
let res = exp_q15(-16384);
assert!((res as i32 - 19874).abs() < 10, "exp(-0.5): attendu ≈19874, reçu {}", res);
}
#[test]
fn test_exp_negative_one() {
let res = exp_q15(-32768);
assert!((res as i32 - 12054).abs() < 10, "exp(-1.0): attendu ≈12054, reçu {}", res);
}
#[test]
fn test_exp_strictly_positive() {
assert!(exp_q15(-32768) > 0);
assert!(exp_q15(-16384) > 0);
assert!(exp_q15(-1) > 0);
}
#[test]
fn test_exp_monotone() {
let a = exp_q15(-32768); let b = exp_q15(-28672); let c = exp_q15(-24576); let d = exp_q15(-16384); let e = exp_q15(-8192); assert!(a < b, "exp(-1.0)={} doit être < exp(-0.875)={}", a, b);
assert!(b < c, "exp(-0.875)={} doit être < exp(-0.75)={}", b, c);
assert!(c < d, "exp(-0.75)={} doit être < exp(-0.5)={}", c, d);
assert!(d < e, "exp(-0.5)={} doit être < exp(-0.25)={}", d, e);
}
}