Path: blob/main/contrib/arm-optimized-routines/math/aarch64/sincospi_4u.c
48255 views
/*1* Double-precision scalar sincospi function.2*3* Copyright (c) 2024, Arm Limited.4* SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception5*/67#include "mathlib.h"8#include "math_config.h"9#include "test_sig.h"10#include "test_defs.h"11#include "poly_scalar_f64.h"1213/* Taylor series coefficents for sin(pi * x).14C2 coefficient (orginally ~=5.16771278) has been split into two parts:15C2_hi = 4, C2_lo = C2 - C2_hi (~=1.16771278)16This change in magnitude reduces floating point rounding errors.17C2_hi is then reintroduced after the polynomial approxmation. */18const static struct sincospi_data19{20double poly[10];21} sincospi_data = {22/* Taylor series coefficents for sin(pi * x). */23.poly = { 0x1.921fb54442d184p1, -0x1.2aef39896f94bp0, 0x1.466bc6775ab16p1,24-0x1.32d2cce62dc33p-1, 0x1.507834891188ep-4, -0x1.e30750a28c88ep-8,250x1.e8f48308acda4p-12, -0x1.6fc0032b3c29fp-16,260x1.af86ae521260bp-21, -0x1.012a9870eeb7dp-25 },27};2829/* Top 12 bits of a double (sign and exponent bits). */30static inline uint64_t31abstop12 (double x)32{33return (asuint64 (x) >> 52) & 0x7ff;34}3536/* Triages special cases into 4 categories:37-1 or +1 if iy represents half an integer38-1 if round(y) is odd.39+1 if round(y) is even.40-2 or +2 if iy represents and integer.41-2 if iy is odd.42+2 if iy is even.43The argument is the bit representation of a positive non-zero44finite floating-point value which is either a half or an integer. */45static inline int46checkint (uint64_t iy)47{48int e = iy >> 52;49if (e > 0x3ff + 52)50return 2;51if (iy & ((1ULL << (0x3ff + 52 - e)) - 1))52{53if ((iy - 1) & 2)54return -1;55else56return 1;57}58if (iy & (1 << (0x3ff + 52 - e)))59return -2;60return 2;61}6263/* Approximation for scalar double-precision sincospi(x).64Maximum error for sin: 3.46 ULP:65sincospif_sin(0x1.3d8a067cd8961p+14) got 0x1.ffe609a279008p-1 want660x1.ffe609a27900cp-1.67Maximum error for cos: 3.66 ULP:68sincospif_cos(0x1.a0ec6997557eep-24) got 0x1.ffffffffffe59p-1 want690x1.ffffffffffe5dp-1. */70void71arm_math_sincospi (double x, double *out_sin, double *out_cos)72{73const struct sincospi_data *d = ptr_barrier (&sincospi_data);74uint64_t sign = asuint64 (x) & 0x8000000000000000;7576if (likely (abstop12 (x) < abstop12 (0x1p51)))77{78/* ax = |x| - n (range reduction into -1/2 .. 1/2). */79double ar_s = x - rint (x);8081/* We know that cospi(x) = sinpi(0.5 - x)82range reduction and offset into sinpi range -1/2 .. 1/283ax = 0.5 - |x - rint(x)|. */84double ar_c = 0.5 - fabs (ar_s);8586/* ss = sin(pi * ax). */87double ar2_s = ar_s * ar_s;88double ar2_c = ar_c * ar_c;89double ar4_s = ar2_s * ar2_s;90double ar4_c = ar2_c * ar2_c;9192uint64_t cc_sign = ((uint64_t) llrint (x)) << 63;93uint64_t ss_sign = cc_sign;94if (ar_s == 0)95ss_sign = sign;9697double ss = pw_horner_9_f64 (ar2_s, ar4_s, d->poly);98double cc = pw_horner_9_f64 (ar2_c, ar4_c, d->poly);99100/* As all values are reduced to -1/2 .. 1/2, the result of cos(x)101always be positive, therefore, the sign must be introduced102based upon if x rounds to odd or even. For sin(x) the sign is103copied from x. */104*out_sin105= asdouble (asuint64 (fma (-4 * ar2_s, ar_s, ss * ar_s)) ^ ss_sign);106*out_cos107= asdouble (asuint64 (fma (-4 * ar2_c, ar_c, cc * ar_c)) ^ cc_sign);108}109else110{111/* When abs(x) > 0x1p51, the x will be either112- Half integer (relevant if abs(x) in [0x1p51, 0x1p52])113- Odd integer (relevant if abs(x) in [0x1p52, 0x1p53])114- Even integer (relevant if abs(x) in [0x1p53, inf])115- Inf or NaN. */116if (abstop12 (x) >= 0x7ff)117{118double inv_result = __math_invalid (x);119*out_sin = inv_result;120*out_cos = inv_result;121return;122}123else124{125uint64_t ax = asuint64 (x) & 0x7fffffffffffffff;126int m = checkint (ax);127/* The case where ax is half integer. */128if (m & 1)129{130*out_sin = sign ? -m : m;131*out_cos = 0;132return;133}134/* The case where ax is integer. */135else136{137*out_sin = asdouble (sign);138*out_cos = m >> 1;139return;140}141}142}143}144145#if WANT_TRIGPI_TESTS146TEST_DISABLE_FENV (arm_math_sincospi_sin)147TEST_DISABLE_FENV (arm_math_sincospi_cos)148TEST_ULP (arm_math_sincospi_sin, 2.96)149TEST_ULP (arm_math_sincospi_cos, 3.16)150# define SINCOS_INTERVAL(lo, hi, n) \151TEST_SYM_INTERVAL (arm_math_sincospi_sin, lo, hi, n) \152TEST_SYM_INTERVAL (arm_math_sincospi_cos, lo, hi, n)153SINCOS_INTERVAL (0, 0x1p-63, 10000)154SINCOS_INTERVAL (0x1p-63, 0.5, 50000)155SINCOS_INTERVAL (0.5, 0x1p51, 50000)156SINCOS_INTERVAL (0x1p51, inf, 10000)157#endif158159160