///| Compute hyperbolic tangent function of a single-precision floating point number.
///
/// # Examples
///
/// ```moonbit
/// 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 = ix.reinterpret_as_float()
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) {
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)
}