1 /* 2 * Single-precision acosh(x) function. 3 * 4 * Copyright (c) 2022-2024, Arm Limited. 5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception 6 */ 7 8 #include "math_config.h" 9 #include "test_sig.h" 10 #include "test_defs.h" 11 12 #define Ln2 (0x1.62e4p-1f) 13 #define MinusZero 0x80000000 14 #define SquareLim 0x5f800000 /* asuint(0x1p64). */ 15 #define Two 0x40000000 16 17 /* acoshf approximation using a variety of approaches on different intervals: 18 19 x >= 2^64: We cannot square x without overflow. For huge x, sqrt(x*x - 1) is 20 close enough to x that we can calculate the result by ln(2x) == ln(x) + 21 ln(2). The greatest error in the region is 0.94 ULP: 22 acoshf(0x1.15f706p+92) got 0x1.022e14p+6 want 0x1.022e16p+6. 23 24 x > 2: Calculate the result directly using definition of asinh(x) = ln(x + 25 sqrt(x*x - 1)). Greatest error in this region is 1.30 ULP: 26 acoshf(0x1.249d8p+1) got 0x1.77e1aep+0 want 0x1.77e1bp+0. 27 28 0 <= x <= 2: Calculate the result using log1p. For x < 1, acosh(x) is 29 undefined. For 1 <= x <= 2, the greatest error is 2.78 ULP: 30 acoshf(0x1.07887p+0) got 0x1.ef9e9cp-3 want 0x1.ef9ea2p-3. */ 31 float 32 acoshf (float x) 33 { 34 uint32_t ix = asuint (x); 35 36 if (unlikely (ix >= MinusZero)) 37 return __math_invalidf (x); 38 39 if (unlikely (ix >= SquareLim)) 40 return logf (x) + Ln2; 41 42 if (ix > Two) 43 return logf (x + sqrtf (x * x - 1)); 44 45 float xm1 = x - 1; 46 return log1pf (xm1 + sqrtf (2 * xm1 + xm1 * xm1)); 47 } 48 49 TEST_SIG (S, F, 1, acosh, 1.0, 10.0) 50 TEST_ULP (acoshf, 2.30) 51 TEST_INTERVAL (acoshf, 0, 1, 100) 52 TEST_INTERVAL (acoshf, 1, 2, 10000) 53 TEST_INTERVAL (acoshf, 2, 0x1p64, 100000) 54 TEST_INTERVAL (acoshf, 0x1p64, inf, 100000) 55 TEST_INTERVAL (acoshf, -0, -inf, 10000) 56