Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/arm-optimized-routines/math/aarch64/experimental/acosh_3u.c
48378 views
1
/*
2
* Double-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 "mathlib.h"
9
#include "math_config.h"
10
#include "test_sig.h"
11
#include "test_defs.h"
12
13
#define Ln2 (0x1.62e42fefa39efp-1)
14
#define MinusZero (0x8000000000000000)
15
#define SquareLim (0x5fe0000000000000) /* asuint64(0x1.0p511). */
16
#define Two (0x4000000000000000) /* asuint64(2.0). */
17
18
/* acosh approximation using a variety of approaches on different intervals:
19
20
acosh(x) = ln(x + sqrt(x * x - 1)).
21
22
x >= 2^511: We cannot square x without overflow. For huge x, sqrt(x*x - 1)
23
is close enough to x that we can calculate the result by ln(2x) == ln(x) +
24
ln(2). The greatest observed error in this region is 0.98 ULP:
25
acosh(0x1.1b9bf42923d1dp+853) got 0x1.28066a11a7c7fp+9
26
want 0x1.28066a11a7c8p+9.
27
28
x > 2: Calculate the result directly using definition of acosh(x). Greatest
29
observed error in this region is 1.33 ULP:
30
acosh(0x1.1e45d14bfcfa2p+1) got 0x1.71a06f50c34b5p+0
31
want 0x1.71a06f50c34b6p+0.
32
33
0 <= x <= 2: Calculate the result using log1p. For x < 1, acosh(x) is
34
undefined. For 1 <= x <= 2, the largest observed error is 2.69 ULP:
35
acosh(0x1.073528248093p+0) got 0x1.e4d9bd20684f3p-3
36
want 0x1.e4d9bd20684f6p-3. */
37
double
38
acosh (double x)
39
{
40
uint64_t ix = asuint64 (x);
41
42
if (unlikely (ix >= MinusZero))
43
return __math_invalid (x);
44
45
if (unlikely (ix >= SquareLim))
46
return log (x) + Ln2;
47
48
if (ix >= Two)
49
return log (x + sqrt (x * x - 1));
50
51
double xm1 = x - 1;
52
return log1p (xm1 + sqrt (2 * xm1 + xm1 * xm1));
53
}
54
55
TEST_SIG (S, D, 1, acosh, 1.0, 10.0)
56
TEST_ULP (acosh, 2.19)
57
TEST_INTERVAL (acosh, 0, 1, 10000)
58
TEST_INTERVAL (acosh, 1, 2, 100000)
59
TEST_INTERVAL (acosh, 2, 0x1p511, 100000)
60
TEST_INTERVAL (acosh, 0x1p511, inf, 100000)
61
TEST_INTERVAL (acosh, -0, -inf, 10000)
62
63