xref: /freebsd/contrib/arm-optimized-routines/math/aarch64/advsimd/asinhf.c (revision dd21556857e8d40f66bf5ad54754d9d52669ebf7)
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
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.  */
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