///|
/// Compute hyperbolic tangent function of a single-precision floating point number.
///
/// # Examples
///
/// ```moonbit nocheck
/// assert_eq(tanhf(-0.5), -0.46211713552474976)
/// assert_eq(tanhf(0.5), 0.46211713552474976)
/// assert_eq(tanhf(0.0), 0.0)
/// assert_eq(tanhf(1), 0.7615941559557649)
/// assert_eq(tanhf(2), 0.9640275800758169)
/// ```
///
/// # Special Cases
///
/// 1. tanhf(NaN) = NaN
/// 2. tanhf(+inf) = 1
/// 3. tanhf(-inf) = -1
///
/// # Accuracy
///
/// 2 ulp.
pub fn tanhf(x : Float) -> Float {
// x = |x| */
let mut ix = x.reinterpret_as_uint()
let sign = ix >> 31 != 0
ix = ix & 0x7fffffff
let x = Float::reinterpret_from_uint(ix)
let w = ix
let tt = if w > 0x3f0c9f54 {
// |x| > log(3)/2 ~= 0.5493 or nan */
if w > 0x41200000 {
// |x| > 10 */
(1.0 : Float) + (0.0 : Float) / x
} else {
let t = expm1f(x * 2.0)
(1.0 : Float) - (2.0 : Float) / (t + 2.0)
}
} else if w > 0x3e82c578 {
// |x| > log(5/3)/2 ~= 0.2554 */
let t = expm1f(x * 2.0)
t / (t + 2.0)
} else if w >= 0x00800000 {
// |x| >= 0x1p-126 */
let t = expm1f(x * -2.0)
-t / (t + 2.0)
} else {
// |x| is subnormal */
//force_eval!(x * x);
x
}
if sign {
-tt
} else {
tt
}
}
///|
test "tanhf" {
fn assert_tanhf_ulp(input, expect) raise {
assert_float_ulp(expect, tanhf(input), TANH_F_MAX_ULP)
}
assert_tanhf_ulp(-1, -0.7615941762924194)
assert_tanhf_ulp(1, 0.7615941762924194)
assert_tanhf_ulp(8, 0.9999997615814209)
assert_tanhf_ulp(-8, -0.9999997615814209)
assert_tanhf_ulp(0, 0)
assert_tanhf_ulp(27, 1)
assert_tanhf_ulp(-27, -1)
assert_tanhf_ulp(0.125, 0.12435300648212433)
assert_tanhf_ulp(-0.125, -0.12435300648212433)
assert_tanhf_ulp(0.5, 0.46211713552474976)
assert_tanhf_ulp(-0.5, -0.46211713552474976)
assert_tanhf_ulp(1.5, 0.9051482677459717)
assert_tanhf_ulp(-1.5, -0.9051482677459717)
assert_tanhf_ulp(2, 0.9640275835990906)
assert_tanhf_ulp(-2, -0.9640275835990906)
assert_tanhf_ulp(3, 0.9950547814369202)
assert_tanhf_ulp(-3, -0.9950547814369202)
assert_tanhf_ulp(64, 1)
assert_tanhf_ulp(-64, -1)
assert_tanhf_ulp(1000, 1)
assert_tanhf_ulp(-1000, -1)
assert_tanhf_ulp(512, 1)
assert_tanhf_ulp(729, 1)
assert_tanhf_ulp(3511808, 1)
assert_tanhf_ulp(15.25, 1)
assert_tanhf_ulp(6859, 1)
assert_tanhf_ulp(68.25, 1)
assert_tanhf_ulp(701.625, 1)
assert_tanhf_ulp(@float.not_a_number, @float.not_a_number)
assert_tanhf_ulp(@float.infinity, 1)
assert_tanhf_ulp(@float.neg_infinity, -1)
}