1 /*
2 * Double-precision vector sincos function.
3 *
4 * Copyright (c) 2023-2024, Arm Limited.
5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6 */
7
8 /* Define _GNU_SOURCE in order to include sincos declaration. If building
9 pre-GLIBC 2.1, or on a non-GNU conforming system, this routine will need to
10 be linked against the scalar sincosf from math/. */
11 #define _GNU_SOURCE
12 #include <math.h>
13
14 #include "v_math.h"
15 #include "test_defs.h"
16 #include "v_sincos_common.h"
17
18 /* sincos not available for all scalar libm implementations. */
19 #if defined(_MSC_VER) || !defined(__GLIBC__)
20 static void
sincos(double x,double * out_sin,double * out_cos)21 sincos (double x, double *out_sin, double *out_cos)
22 {
23 *out_sin = sin (x);
24 *out_cos = cos (x);
25 }
26 #endif
27
28 static void VPCS_ATTR NOINLINE
special_case(float64x2_t x,uint64x2_t special,double * out_sin,double * out_cos)29 special_case (float64x2_t x, uint64x2_t special, double *out_sin,
30 double *out_cos)
31 {
32 if (special[0])
33 sincos (x[0], out_sin, out_cos);
34 if (special[1])
35 sincos (x[1], out_sin + 1, out_cos + 1);
36 }
37
38 /* Double-precision vector function allowing calculation of both sin and cos in
39 one function call, using shared argument reduction and separate polynomials.
40 Largest observed error is for sin, 3.22 ULP:
41 v_sincos_sin (0x1.d70eef40f39b1p+12) got -0x1.ffe9537d5dbb7p-3
42 want -0x1.ffe9537d5dbb4p-3. */
43 VPCS_ATTR void
_ZGVnN2vl8l8_sincos(float64x2_t x,double * out_sin,double * out_cos)44 _ZGVnN2vl8l8_sincos (float64x2_t x, double *out_sin, double *out_cos)
45 {
46 const struct v_sincos_data *d = ptr_barrier (&v_sincos_data);
47 uint64x2_t special = check_ge_rangeval (x, d);
48
49 float64x2x2_t sc = v_sincos_inline (x, d);
50
51 vst1q_f64 (out_sin, sc.val[0]);
52 vst1q_f64 (out_cos, sc.val[1]);
53
54 if (unlikely (v_any_u64 (special)))
55 special_case (x, special, out_sin, out_cos);
56 }
57
58 TEST_DISABLE_FENV (_ZGVnN2v_sincos_cos)
59 TEST_DISABLE_FENV (_ZGVnN2v_sincos_sin)
60 TEST_ULP (_ZGVnN2v_sincos_sin, 2.73)
61 TEST_ULP (_ZGVnN2v_sincos_cos, 2.73)
62 #define V_SINCOS_INTERVAL(lo, hi, n) \
63 TEST_INTERVAL (_ZGVnN2v_sincos_sin, lo, hi, n) \
64 TEST_INTERVAL (_ZGVnN2v_sincos_cos, lo, hi, n)
65 V_SINCOS_INTERVAL (0, 0x1p-31, 50000)
66 V_SINCOS_INTERVAL (0x1p-31, 0x1p23, 500000)
67 V_SINCOS_INTERVAL (0x1p23, inf, 10000)
68