1 /*
2 * Single-precision vector asinh(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 "v_math.h"
9 #include "test_sig.h"
10 #include "test_defs.h"
11 #include "v_log1pf_inline.h"
12
13 const static struct data
14 {
15 struct v_log1pf_data log1pf_consts;
16 float32x4_t one;
17 uint32x4_t big_bound;
18 #if WANT_SIMD_EXCEPT
19 uint32x4_t tiny_bound;
20 #endif
21 } data = {
22 .one = V4 (1),
23 .log1pf_consts = V_LOG1PF_CONSTANTS_TABLE,
24 .big_bound = V4 (0x5f800000), /* asuint(0x1p64). */
25 #if WANT_SIMD_EXCEPT
26 .tiny_bound = V4 (0x30800000) /* asuint(0x1p-30). */
27 #endif
28 };
29
30 static float32x4_t NOINLINE VPCS_ATTR
special_case(float32x4_t x,uint32x4_t sign,float32x4_t y,uint32x4_t special,const struct data * d)31 special_case (float32x4_t x, uint32x4_t sign, float32x4_t y,
32 uint32x4_t special, const struct data *d)
33 {
34 return v_call_f32 (
35 asinhf, x,
36 vreinterpretq_f32_u32 (veorq_u32 (
37 sign, vreinterpretq_u32_f32 (log1pf_inline (y, &d->log1pf_consts)))),
38 special);
39 }
40
41 /* Single-precision implementation of vector asinh(x), using vector log1p.
42 Worst-case error is 2.59 ULP:
43 _ZGVnN4v_asinhf(0x1.d86124p-3) got 0x1.d449bep-3
44 want 0x1.d449c4p-3. */
V_NAME_F1(asinh)45 float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (asinh) (float32x4_t x)
46 {
47 const struct data *dat = ptr_barrier (&data);
48 float32x4_t ax = vabsq_f32 (x);
49 uint32x4_t iax = vreinterpretq_u32_f32 (ax);
50 uint32x4_t special = vcgeq_u32 (iax, dat->big_bound);
51 uint32x4_t sign = veorq_u32 (vreinterpretq_u32_f32 (x), iax);
52 float32x4_t special_arg = x;
53
54 #if WANT_SIMD_EXCEPT
55 /* Sidestep tiny and large values to avoid inadvertently triggering
56 under/overflow. */
57 special = vorrq_u32 (special, vcltq_u32 (iax, dat->tiny_bound));
58 if (unlikely (v_any_u32 (special)))
59 {
60 ax = v_zerofy_f32 (ax, special);
61 x = v_zerofy_f32 (x, special);
62 }
63 #endif
64
65 /* asinh(x) = log(x + sqrt(x * x + 1)).
66 For positive x, asinh(x) = log1p(x + x * x / (1 + sqrt(x * x + 1))). */
67 float32x4_t d
68 = vaddq_f32 (v_f32 (1), vsqrtq_f32 (vfmaq_f32 (dat->one, ax, ax)));
69 float32x4_t y = vaddq_f32 (ax, vdivq_f32 (vmulq_f32 (ax, ax), d));
70
71 if (unlikely (v_any_u32 (special)))
72 return special_case (special_arg, sign, y, special, dat);
73 return vreinterpretq_f32_u32 (veorq_u32 (
74 sign, vreinterpretq_u32_f32 (log1pf_inline (y, &dat->log1pf_consts))));
75 }
76
77 HALF_WIDTH_ALIAS_F1 (asinh)
78
79 TEST_SIG (V, F, 1, asinh, -10.0, 10.0)
80 TEST_ULP (V_NAME_F1 (asinh), 2.10)
81 TEST_DISABLE_FENV_IF_NOT (V_NAME_F1 (asinh), WANT_SIMD_EXCEPT)
82 TEST_INTERVAL (V_NAME_F1 (asinh), 0, 0x1p-12, 40000)
83 TEST_INTERVAL (V_NAME_F1 (asinh), 0x1p-12, 1.0, 40000)
84 TEST_INTERVAL (V_NAME_F1 (asinh), 1.0, 0x1p11, 40000)
85 TEST_INTERVAL (V_NAME_F1 (asinh), 0x1p11, inf, 40000)
86 TEST_INTERVAL (V_NAME_F1 (asinh), -0, -0x1p-12, 20000)
87 TEST_INTERVAL (V_NAME_F1 (asinh), -0x1p-12, -1.0, 20000)
88 TEST_INTERVAL (V_NAME_F1 (asinh), -1.0, -0x1p11, 20000)
89 TEST_INTERVAL (V_NAME_F1 (asinh), -0x1p11, -inf, 20000)
90