1 /* 2 * Single-precision vector cosh(x) function. 3 * 4 * Copyright (c) 2022-2023, Arm Limited. 5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception 6 */ 7 8 #include "v_math.h" 9 #include "mathlib.h" 10 #include "pl_sig.h" 11 #include "pl_test.h" 12 13 #define AbsMask 0x7fffffff 14 #define TinyBound 0x20000000 /* 0x1p-63: Round to 1 below this. */ 15 #define SpecialBound \ 16 0x42ad496c /* 0x1.5a92d8p+6: expf overflows above this, so have to use \ 17 special case. */ 18 #define Half v_f32 (0.5) 19 20 #if V_SUPPORTED 21 22 v_f32_t V_NAME (expf) (v_f32_t); 23 24 /* Single-precision vector cosh, using vector expf. 25 Maximum error is 2.38 ULP: 26 __v_coshf(0x1.e8001ep+1) got 0x1.6a491ep+4 want 0x1.6a4922p+4. */ 27 VPCS_ATTR v_f32_t V_NAME (coshf) (v_f32_t x) 28 { 29 v_u32_t ix = v_as_u32_f32 (x); 30 v_u32_t iax = ix & AbsMask; 31 v_f32_t ax = v_as_f32_u32 (iax); 32 v_u32_t special = v_cond_u32 (iax >= SpecialBound); 33 34 #if WANT_SIMD_EXCEPT 35 /* If fp exceptions are to be triggered correctly, fall back to the scalar 36 variant for all inputs if any input is a special value or above the bound 37 at which expf overflows. */ 38 if (unlikely (v_any_u32 (special))) 39 return v_call_f32 (coshf, x, x, v_u32 (-1)); 40 41 v_u32_t tiny = v_cond_u32 (iax <= TinyBound); 42 /* If any input is tiny, avoid underflow exception by fixing tiny lanes of 43 input to 1, which will generate no exceptions, and then also fixing tiny 44 lanes of output to 1 just before return. */ 45 if (unlikely (v_any_u32 (tiny))) 46 ax = v_sel_f32 (tiny, v_f32 (1), ax); 47 #endif 48 49 /* Calculate cosh by exp(x) / 2 + exp(-x) / 2. */ 50 v_f32_t t = V_NAME (expf) (ax); 51 v_f32_t y = t * Half + Half / t; 52 53 #if WANT_SIMD_EXCEPT 54 if (unlikely (v_any_u32 (tiny))) 55 return v_sel_f32 (tiny, v_f32 (1), y); 56 #else 57 if (unlikely (v_any_u32 (special))) 58 return v_call_f32 (coshf, x, y, special); 59 #endif 60 61 return y; 62 } 63 VPCS_ALIAS 64 65 PL_SIG (V, F, 1, cosh, -10.0, 10.0) 66 PL_TEST_ULP (V_NAME (coshf), 1.89) 67 PL_TEST_EXPECT_FENV (V_NAME (coshf), WANT_SIMD_EXCEPT) 68 PL_TEST_INTERVAL (V_NAME (coshf), 0, 0x1p-63, 100) 69 PL_TEST_INTERVAL (V_NAME (coshf), 0, 0x1.5a92d8p+6, 80000) 70 PL_TEST_INTERVAL (V_NAME (coshf), 0x1.5a92d8p+6, inf, 2000) 71 PL_TEST_INTERVAL (V_NAME (coshf), -0, -0x1p-63, 100) 72 PL_TEST_INTERVAL (V_NAME (coshf), -0, -0x1.5a92d8p+6, 80000) 73 PL_TEST_INTERVAL (V_NAME (coshf), -0x1.5a92d8p+6, -inf, 2000) 74 #endif 75