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. */
V_NAME(coshf)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