///| Compute the inverse hyperbolic sine of `x` with single-precision floating-point.
///
/// Computes the inverse hyperbolic sine of `x`. The inverse hyperbolic sine is defined as:
/// $$\text{asinh}(x) = \log(x + \sqrt{x^2 + 1})$$
///
/// # Examples
///
/// ```moonbit
/// assert_eq!(asinhf(-1), -0.881373587019543)
/// assert_eq!(asinhf(-2), -1.4436354751788103)
/// assert_eq!(asinhf(1), 0.881373587019543)
/// assert_eq!(asinhf(2), 1.4436354751788103)
/// ```
///
/// # Special Cases
///
/// 1. asinhf(NaN) = NaN.
/// 2. asinhf(±0) = ±0.
/// 3. asinhf(±∞) = ±∞.
///
/// # Accuracy
///
/// 1 ulp (unit in the last place).
pub fn asinhf(x : Float) -> Float {
let u = x.reinterpret_as_uint()
let i = u & 0x7fffffff
let sign = (u >> 31) != 0
let ln2 : Float = 0.693147180559945309417232121458176568
// |x| */
let x = i.reinterpret_as_float()
let x = if i >= 0x3f800000U + (12U << 23) {
// |x| >= 0x1p12 or inf or nan */
logf(x) + ln2
} else if i >= 0x3f800000U + (1U << 23) {
// |x| >= 2 */
logf(x * 2.0 + recipf(sqrtf(x * x + 1.0) + x))
} else if i >= 0x3f800000U - (12U << 23) {
// |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */
log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0))
} else {
// |x| < 0x1p-12, raise inexact if x!=0 */
// x + 0x1.0p120
x
}
if sign {
-x
} else {
x
}
}
///|
test "asinhf" {
fn assert_asinhf_ulp!(input, expect) {
assert_float_ulp!(expect, asinhf(input), ASINH_F_MAX_ULP)
}
assert_asinhf_ulp!(-1, -0.8813735842704773)
assert_asinhf_ulp!(1, 0.8813735842704773)
assert_asinhf_ulp!(8, 2.776472330093384)
assert_asinhf_ulp!(-8, -2.776472330093384)
assert_asinhf_ulp!(0, 0)
assert_asinhf_ulp!(27, 3.9893267154693604)
assert_asinhf_ulp!(-27, -3.9893267154693604)
assert_asinhf_ulp!(0.125, 0.12467674911022186)
assert_asinhf_ulp!(-0.125, -0.12467674911022186)
assert_asinhf_ulp!(0.5, 0.4812118411064148)
assert_asinhf_ulp!(-0.5, -0.4812118411064148)
assert_asinhf_ulp!(1.5, 1.19476318359375)
assert_asinhf_ulp!(-1.5, -1.19476318359375)
assert_asinhf_ulp!(2, 1.4436354637145996)
assert_asinhf_ulp!(-2, -1.4436354637145996)
assert_asinhf_ulp!(3, 1.818446397781372)
assert_asinhf_ulp!(-3, -1.818446397781372)
assert_asinhf_ulp!(64, 4.852091312408447)
assert_asinhf_ulp!(-64, -4.852091312408447)
assert_asinhf_ulp!(1000, 7.600902557373047)
assert_asinhf_ulp!(-1000, -7.600902557373047)
assert_asinhf_ulp!(512, 6.9314727783203125)
assert_asinhf_ulp!(729, 7.284821510314941)
assert_asinhf_ulp!(3511808, 15.764789581298828)
assert_asinhf_ulp!(15.25, 3.418799877166748)
assert_asinhf_ulp!(6859, 9.526464462280273)
assert_asinhf_ulp!(68.25, 4.916378498077393)
assert_asinhf_ulp!(701.625, 7.246546745300293)
assert_asinhf_ulp!(@float.not_a_number, @float.not_a_number)
assert_asinhf_ulp!(@float.infinity, @float.infinity)
assert_asinhf_ulp!(@float.neg_infinity, @float.neg_infinity)
}