1*f3087befSAndrew Turner /*
2*f3087befSAndrew Turner * Helper for Double-precision vector sincospi function.
3*f3087befSAndrew Turner *
4*f3087befSAndrew Turner * Copyright (c) 2024, Arm Limited.
5*f3087befSAndrew Turner * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6*f3087befSAndrew Turner */
7*f3087befSAndrew Turner #include "v_math.h"
8*f3087befSAndrew Turner #include "v_poly_f64.h"
9*f3087befSAndrew Turner
10*f3087befSAndrew Turner static const struct v_sincospi_data
11*f3087befSAndrew Turner {
12*f3087befSAndrew Turner float64x2_t poly[10], range_val;
13*f3087befSAndrew Turner } v_sincospi_data = {
14*f3087befSAndrew Turner /* Polynomial coefficients generated using Remez algorithm,
15*f3087befSAndrew Turner see sinpi.sollya for details. */
16*f3087befSAndrew Turner .poly = { V2 (0x1.921fb54442d184p1), V2 (-0x1.4abbce625be53p2),
17*f3087befSAndrew Turner V2 (0x1.466bc6775ab16p1), V2 (-0x1.32d2cce62dc33p-1),
18*f3087befSAndrew Turner V2 (0x1.507834891188ep-4), V2 (-0x1.e30750a28c88ep-8),
19*f3087befSAndrew Turner V2 (0x1.e8f48308acda4p-12), V2 (-0x1.6fc0032b3c29fp-16),
20*f3087befSAndrew Turner V2 (0x1.af86ae521260bp-21), V2 (-0x1.012a9870eeb7dp-25) },
21*f3087befSAndrew Turner .range_val = V2 (0x1p63),
22*f3087befSAndrew Turner };
23*f3087befSAndrew Turner
24*f3087befSAndrew Turner /* Double-precision vector function allowing calculation of both sin and cos in
25*f3087befSAndrew Turner one function call, using separate argument reduction and shared low-order
26*f3087befSAndrew Turner polynomials.
27*f3087befSAndrew Turner Approximation for vector double-precision sincospi(x).
28*f3087befSAndrew Turner Maximum Error 3.09 ULP:
29*f3087befSAndrew Turner _ZGVnN2v_sincospi_sin(0x1.7a41deb4b21e1p+14) got 0x1.fd54d0b327cf1p-1
30*f3087befSAndrew Turner want 0x1.fd54d0b327cf4p-1
31*f3087befSAndrew Turner Maximum Error 3.16 ULP:
32*f3087befSAndrew Turner _ZGVnN2v_sincospi_cos(-0x1.11e3c7e284adep-5) got 0x1.fd2da484ff3ffp-1
33*f3087befSAndrew Turner want 0x1.fd2da484ff402p-1. */
34*f3087befSAndrew Turner static inline float64x2x2_t
v_sincospi_inline(float64x2_t x,const struct v_sincospi_data * d)35*f3087befSAndrew Turner v_sincospi_inline (float64x2_t x, const struct v_sincospi_data *d)
36*f3087befSAndrew Turner {
37*f3087befSAndrew Turner /* If r is odd, the sign of the result should be inverted for sinpi
38*f3087befSAndrew Turner and reintroduced for cospi. */
39*f3087befSAndrew Turner uint64x2_t cmp = vcgeq_f64 (x, d->range_val);
40*f3087befSAndrew Turner uint64x2_t odd = vshlq_n_u64 (
41*f3087befSAndrew Turner vbicq_u64 (vreinterpretq_u64_s64 (vcvtaq_s64_f64 (x)), cmp), 63);
42*f3087befSAndrew Turner
43*f3087befSAndrew Turner /* r = x - rint(x). */
44*f3087befSAndrew Turner float64x2_t sr = vsubq_f64 (x, vrndaq_f64 (x));
45*f3087befSAndrew Turner /* cospi(x) = sinpi(0.5 - abs(x)) for values -1/2 .. 1/2. */
46*f3087befSAndrew Turner float64x2_t cr = vsubq_f64 (v_f64 (0.5), vabsq_f64 (sr));
47*f3087befSAndrew Turner
48*f3087befSAndrew Turner /* Pairwise Horner approximation for y = sin(r * pi). */
49*f3087befSAndrew Turner float64x2_t sr2 = vmulq_f64 (sr, sr);
50*f3087befSAndrew Turner float64x2_t sr4 = vmulq_f64 (sr2, sr2);
51*f3087befSAndrew Turner float64x2_t cr2 = vmulq_f64 (cr, cr);
52*f3087befSAndrew Turner float64x2_t cr4 = vmulq_f64 (cr2, cr2);
53*f3087befSAndrew Turner
54*f3087befSAndrew Turner float64x2_t ss = vmulq_f64 (v_pw_horner_9_f64 (sr2, sr4, d->poly), sr);
55*f3087befSAndrew Turner float64x2_t cc = vmulq_f64 (v_pw_horner_9_f64 (cr2, cr4, d->poly), cr);
56*f3087befSAndrew Turner
57*f3087befSAndrew Turner float64x2_t sinpix
58*f3087befSAndrew Turner = vreinterpretq_f64_u64 (veorq_u64 (vreinterpretq_u64_f64 (ss), odd));
59*f3087befSAndrew Turner
60*f3087befSAndrew Turner float64x2_t cospix
61*f3087befSAndrew Turner = vreinterpretq_f64_u64 (veorq_u64 (vreinterpretq_u64_f64 (cc), odd));
62*f3087befSAndrew Turner
63*f3087befSAndrew Turner return (float64x2x2_t){ sinpix, cospix };
64*f3087befSAndrew Turner }
65