Path: blob/main/contrib/arm-optimized-routines/math/aarch64/tanpi_2u5.c
48255 views
/*1* Double-precision scalar tanpi(x) function.2*3* Copyright (c) 2024, Arm Limited.4* SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception5*/6#include "mathlib.h"7#include "math_config.h"8#include "test_sig.h"9#include "test_defs.h"10#include "poly_scalar_f64.h"1112#define SIGN_MASK 0x80000000000000001314const static struct tanpi_data15{16double tan_poly[14], cot_poly[9], pi, invpi;17} tanpi_data = {18/* Coefficents for tan(pi * x). */19.tan_poly = {200x1.4abbce625be52p3,210x1.466bc6775b0f9p5,220x1.45fff9b426f5ep7,230x1.45f4730dbca5cp9,240x1.45f3265994f85p11,250x1.45f4234b330cap13,260x1.45dca11be79ebp15,270x1.47283fc5eea69p17,280x1.3a6d958cdefaep19,290x1.927896baee627p21,30-0x1.89333f6acd922p19,310x1.5d4e912bb8456p27,32-0x1.a854d53ab6874p29,330x1.1b76de7681424p32,34},35/* Coefficents for cot(pi * x). */36.cot_poly = {37-0x1.0c152382d7366p0,38-0x1.60c8539c1d316p-1,39-0x1.4b9a2f3516354p-1,40-0x1.47474060b6ba8p-1,41-0x1.464633ad9dcb1p-1,42-0x1.45ff229d7edd6p-1,43-0x1.46d8dbf492923p-1,44-0x1.3873892311c6bp-1,45-0x1.b2f3d0ff96d73p-1,46},47.pi = 0x1.921fb54442d18p1,48.invpi = 0x1.45f306dc9c883p-2,49};5051/* Double-precision scalar tanpi(x) implementation.52Maximum error 2.19 ULP:53tanpi(0x1.68847e177a855p-2) got 0x1.fe9a0ff9bb9d7p+054want 0x1.fe9a0ff9bb9d5p+0. */55double56arm_math_tanpi (double x)57{58uint64_t xabs_12 = asuint64 (x) >> 52 & 0x7ff;5960/* x >= 0x1p54. */61if (unlikely (xabs_12 >= 0x434))62{63/* tanpi(+/-inf) and tanpi(+/-nan) = nan. */64if (unlikely (xabs_12 == 0x7ff))65{66return __math_invalid (x);67}6869uint64_t x_sign = asuint64 (x) & SIGN_MASK;70return asdouble (x_sign);71}7273const struct tanpi_data *d = ptr_barrier (&tanpi_data);7475double rounded = round (x);76if (unlikely (rounded == x))77{78/* If x == 0, return with sign. */79if (x == 0)80{81return x;82}83/* Otherwise, return zero with alternating sign. */84int64_t m = (int64_t) rounded;85if (x < 0)86{87return m & 1 ? 0.0 : -0.0;88}89else90{91return m & 1 ? -0.0 : 0.0;92}93}9495double x_reduced = x - rounded;96double abs_x_reduced = 0.5 - fabs (x_reduced);9798/* Prevent underflow exceptions. x <= 0x1p-63. */99if (unlikely (xabs_12 < 0x3c0))100{101return d->pi * x;102}103104double result, offset, scale;105106/* Test 0.25 < abs_x < 0.5 independent from abs_x_reduced. */107double x2 = x + x;108int64_t rounded_x2 = (int64_t) round (x2);109if (rounded_x2 & 1)110{111double r_x = abs_x_reduced;112113double r_x2 = r_x * r_x;114double r_x4 = r_x2 * r_x2;115116uint64_t sign = asuint64 (x_reduced) & SIGN_MASK;117r_x = asdouble (asuint64 (r_x) ^ sign);118119// calculate sign for half-fractional inf values120uint64_t is_finite = asuint64 (abs_x_reduced);121uint64_t is_odd = (rounded_x2 & 2) << 62;122uint64_t is_neg = rounded_x2 & SIGN_MASK;123uint64_t keep_sign = is_finite | (is_odd ^ is_neg);124offset = d->invpi / (keep_sign ? r_x : -r_x);125scale = r_x;126127result = pw_horner_8_f64 (r_x2, r_x4, d->cot_poly);128}129else130{131double r_x2 = x_reduced * x_reduced;132double r_x4 = r_x2 * r_x2;133134offset = d->pi * x_reduced;135scale = x_reduced * r_x2;136137result = pw_horner_13_f64 (r_x2, r_x4, d->tan_poly);138}139140return fma (scale, result, offset);141}142143#if WANT_EXPERIMENTAL_MATH144double145tanpi (double x)146{147return arm_math_tanpi (x);148}149#endif150151#if WANT_TRIGPI_TESTS152TEST_ULP (arm_math_tanpi, 1.69)153TEST_SYM_INTERVAL (arm_math_tanpi, 0, 0x1p-63, 50000)154TEST_SYM_INTERVAL (arm_math_tanpi, 0x1p-63, 0.5, 100000)155TEST_SYM_INTERVAL (arm_math_tanpi, 0.5, 0x1p53, 100000)156TEST_SYM_INTERVAL (arm_math_tanpi, 0x1p53, inf, 100000)157#endif158159160