use crate::math;
#[inline]
pub fn tanh_inplace(slice: &mut [f64]) {
for x in slice.iter_mut() {
*x = math::tanh(*x);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::math;
#[test]
fn tanh_inplace_matches_elementwise() {
let inputs = [-100.0, -3.0, -1.0, -0.5, 0.0, 0.5, 1.0, 3.0, 100.0];
let mut slice = inputs;
tanh_inplace(&mut slice);
for (&original, &result) in inputs.iter().zip(slice.iter()) {
let expected = math::tanh(original);
assert!(
(result - expected).abs() < 1e-15,
"tanh_inplace({original}) = {result}, expected {expected}"
);
}
}
#[test]
fn output_is_bounded_in_unit_interval() {
let mut extremes = [f64::MIN_POSITIVE, -1e300, 0.0, 1e300, f64::MAX / 2.0];
tanh_inplace(&mut extremes);
for &x in &extremes {
assert!(
(-1.0..=1.0).contains(&x),
"tanh output {x} must be in [-1, 1] (IEEE-754: exact ±1.0 is allowed at extremes)"
);
}
}
#[test]
fn empty_slice_is_noop() {
let mut empty: [f64; 0] = [];
tanh_inplace(&mut empty); }
#[test]
fn zero_maps_to_zero() {
let mut slice = [0.0f64];
tanh_inplace(&mut slice);
assert_eq!(slice[0], 0.0);
}
#[test]
fn single_application_equals_tanh() {
let originals = [0.5f64, -0.5, 2.0, -2.0];
let mut slice = originals;
tanh_inplace(&mut slice);
for (&orig, &result) in originals.iter().zip(slice.iter()) {
let expected = math::tanh(orig);
assert!(
(result - expected).abs() < 1e-15,
"tanh_inplace({orig}) = {result}, expected {expected}"
);
}
}
}