xref: /freebsd/contrib/arm-optimized-routines/math/aarch64/sve/coshf.c (revision f3087bef11543b42e0d69b708f367097a4118d24)
1 /*
2  * Single-precision SVE cosh(x) function.
3  *
4  * Copyright (c) 2023-2024, Arm Limited.
5  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6  */
7 
8 #include "sv_math.h"
9 #include "test_sig.h"
10 #include "test_defs.h"
11 #include "sv_expf_inline.h"
12 
13 static const struct data
14 {
15   struct sv_expf_data expf_consts;
16   float special_bound;
17 } data = {
18   .expf_consts = SV_EXPF_DATA,
19   /* 0x1.5a92d8p+6: expf overflows above this, so have to use special case.  */
20   .special_bound = 0x1.5a92d8p+6,
21 };
22 
23 static svfloat32_t NOINLINE
special_case(svfloat32_t x,svfloat32_t half_e,svfloat32_t half_over_e,svbool_t pg)24 special_case (svfloat32_t x, svfloat32_t half_e, svfloat32_t half_over_e,
25 	      svbool_t pg)
26 {
27   return sv_call_f32 (coshf, x, svadd_x (svptrue_b32 (), half_e, half_over_e),
28 		      pg);
29 }
30 
31 /* Single-precision vector cosh, using vector expf.
32    Maximum error is 2.77 ULP:
33    _ZGVsMxv_coshf(-0x1.5b38f4p+1) got 0x1.e45946p+2
34 				 want 0x1.e4594cp+2.  */
SV_NAME_F1(cosh)35 svfloat32_t SV_NAME_F1 (cosh) (svfloat32_t x, svbool_t pg)
36 {
37   const struct data *d = ptr_barrier (&data);
38 
39   svbool_t special = svacge (pg, x, d->special_bound);
40 
41   /* Calculate cosh by exp(x) / 2 + exp(-x) / 2.
42      Note that x is passed to exp here, rather than |x|. This is to avoid using
43      destructive unary ABS for better register usage. However it means the
44      routine is not exactly symmetrical, as the exp helper is slightly less
45      accurate in the negative range.  */
46   svfloat32_t e = expf_inline (x, pg, &d->expf_consts);
47   svfloat32_t half_e = svmul_x (svptrue_b32 (), e, 0.5);
48   svfloat32_t half_over_e = svdivr_x (pg, e, 0.5);
49 
50   if (unlikely (svptest_any (pg, special)))
51     return special_case (x, half_e, half_over_e, special);
52 
53   return svadd_x (svptrue_b32 (), half_e, half_over_e);
54 }
55 
56 TEST_SIG (SV, F, 1, cosh, -10.0, 10.0)
57 TEST_ULP (SV_NAME_F1 (cosh), 2.28)
58 TEST_DISABLE_FENV (SV_NAME_F1 (cosh))
59 TEST_SYM_INTERVAL (SV_NAME_F1 (cosh), 0, 0x1p-63, 100)
60 TEST_SYM_INTERVAL (SV_NAME_F1 (cosh), 0, 0x1.5a92d8p+6, 80000)
61 TEST_SYM_INTERVAL (SV_NAME_F1 (cosh), 0x1.5a92d8p+6, inf, 2000)
62 CLOSE_SVE_ATTR
63