Path: blob/main/contrib/arm-optimized-routines/math/aarch64/sincospif_3u2.c
48255 views
/*1* Single-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 "math_config.h"8#include "test_sig.h"9#include "test_defs.h"10#include "poly_scalar_f32.h"1112/* Taylor series coefficents for sin(pi * x). */13const static struct sincospif_data14{15float poly[6];16} sincospif_data = {17/* Taylor series coefficents for sin(pi * x). */18.poly = { 0x1.921fb6p1f, -0x1.4abbcep2f, 0x1.466bc6p1f, -0x1.32d2ccp-1f,190x1.50783p-4f, -0x1.e30750p-8f },20};2122/* Top 12 bits of the float representation with the sign bit cleared. */23static inline uint32_t24abstop12 (float x)25{26return (asuint (x) >> 20) & 0x7ff;27}2829/* Triages special cases into 4 categories:30-1 or +1 if iy represents half an integer31-1 if round(y) is odd.32+1 if round(y) is even.33-2 or +2 if iy represents and integer.34-2 if iy is odd.35+2 if iy is even.36The argument is the bit representation of a positive non-zero37finite floating-point value which is either a half or an integer. */38static inline int39checkint (uint32_t iy)40{41int e = iy >> 23;42if (e > 0x7f + 23)43return 2;44if (iy & ((1 << (0x7f + 23 - e)) - 1))45{46if ((iy - 1) & 2)47return -1;48else49return 1;50}51if (iy & (1 << (0x7f + 23 - e)))52return -2;53return 2;54}5556/* Approximation for scalar single-precision sincospif(x).57Maximum error for sin: 3.04 ULP:58sincospif_sin(0x1.c597ccp-2) got 0x1.f7cd56p-1 want 0x1.f7cd5p-1.59Maximum error for cos: 3.18 ULP:60sincospif_cos(0x1.d341a8p-5) got 0x1.f7cd56p-1 want 0x1.f7cd5p-1. */61void62arm_math_sincospif (float x, float *out_sin, float *out_cos)63{6465const struct sincospif_data *d = ptr_barrier (&sincospif_data);66uint32_t sign = asuint (x) & 0x80000000;6768/* abs(x) in [0, 0x1p22]. */69if (likely (abstop12 (x) < abstop12 (0x1p22)))70{71/* ar_s = x - n (range reduction into -1/2 .. 1/2). */72float ar_s = x - rintf (x);73/* We know that cospi(x) = sinpi(0.5 - x)74range reduction and offset into sinpi range -1/2 .. 1/275ar_c = 0.5 - |x - n|. */76float ar_c = 0.5f - fabsf (ar_s);7778float ar2_s = ar_s * ar_s;79float ar2_c = ar_c * ar_c;80float ar4_s = ar2_s * ar2_s;81float ar4_c = ar2_c * ar2_c;8283uint32_t cc_sign = lrintf (x) << 31;84uint32_t ss_sign = cc_sign;85if (ar_s == 0)86ss_sign = sign;8788/* As all values are reduced to -1/2 .. 1/2, the result of cos(x)89always be positive, therefore, the sign must be introduced90based upon if x rounds to odd or even. For sin(x) the sign is91copied from x. */92*out_sin = pw_horner_5_f32 (ar2_s, ar4_s, d->poly)93* asfloat (asuint (ar_s) ^ ss_sign);94*out_cos = pw_horner_5_f32 (ar2_c, ar4_c, d->poly)95* asfloat (asuint (ar_c) ^ cc_sign);96return;97}98else99{100/* When abs(x) > 0x1p22, the x will be either101- Half integer (relevant if abs(x) in [0x1p22, 0x1p23])102- Odd integer (relevant if abs(x) in [0x1p22, 0x1p24])103- Even integer (relevant if abs(x) in [0x1p22, inf])104- Inf or NaN. */105if (abstop12 (x) >= 0x7f8)106{107float inv_result = __math_invalidf (x);108*out_sin = inv_result;109*out_cos = inv_result;110return;111}112else113{114uint32_t ax = asuint (x) & 0x7fffffff;115int m = checkint (ax);116if (m & 1)117{118*out_sin = sign ? -m : m;119*out_cos = 0;120return;121}122else123{124*out_sin = asfloat (sign);125*out_cos = m >> 1;126return;127}128}129}130}131132#if WANT_TRIGPI_TESTS133TEST_DISABLE_FENV (arm_math_sincospif_sin)134TEST_DISABLE_FENV (arm_math_sincospif_cos)135TEST_ULP (arm_math_sincospif_sin, 2.54)136TEST_ULP (arm_math_sincospif_cos, 2.68)137# define SINCOSPIF_INTERVAL(lo, hi, n) \138TEST_SYM_INTERVAL (arm_math_sincospif_sin, lo, hi, n) \139TEST_SYM_INTERVAL (arm_math_sincospif_cos, lo, hi, n)140SINCOSPIF_INTERVAL (0, 0x1p-31, 10000)141SINCOSPIF_INTERVAL (0x1p-31, 1, 50000)142SINCOSPIF_INTERVAL (1, 0x1p22f, 50000)143SINCOSPIF_INTERVAL (0x1p22f, inf, 10000)144#endif145146147