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