xref: /freebsd/contrib/arm-optimized-routines/pl/math/v_coshf_2u4.c (revision 9247238cc4b8835892a47701136b0fd073f8d67c)
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