Blame sysdeps/ieee754/ldbl-128ibm/k_sinl.c

Packit 6c4009
/* Quad-precision floating point sine on <-pi/4,pi/4>.
Packit 6c4009
   Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Jakub Jelinek <jj@ultra.linux.cz>
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <float.h>
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <math_private.h>
Packit 6c4009
#include <math-underflow.h>
Packit 6c4009
Packit 6c4009
static const long double c[] = {
Packit 6c4009
#define ONE c[0]
Packit 6c4009
 1.00000000000000000000000000000000000E+00L, /* 3fff0000000000000000000000000000 */
Packit 6c4009
Packit 6c4009
/* cos x ~ ONE + x^2 ( SCOS1 + SCOS2 * x^2 + ... + SCOS4 * x^6 + SCOS5 * x^8 )
Packit 6c4009
   x in <0,1/256>  */
Packit 6c4009
#define SCOS1 c[1]
Packit 6c4009
#define SCOS2 c[2]
Packit 6c4009
#define SCOS3 c[3]
Packit 6c4009
#define SCOS4 c[4]
Packit 6c4009
#define SCOS5 c[5]
Packit 6c4009
-5.00000000000000000000000000000000000E-01L, /* bffe0000000000000000000000000000 */
Packit 6c4009
 4.16666666666666666666666666556146073E-02L, /* 3ffa5555555555555555555555395023 */
Packit 6c4009
-1.38888888888888888888309442601939728E-03L, /* bff56c16c16c16c16c16a566e42c0375 */
Packit 6c4009
 2.48015873015862382987049502531095061E-05L, /* 3fefa01a01a019ee02dcf7da2d6d5444 */
Packit 6c4009
-2.75573112601362126593516899592158083E-07L, /* bfe927e4f5dce637cb0b54908754bde0 */
Packit 6c4009
Packit 6c4009
/* sin x ~ ONE * x + x^3 ( SIN1 + SIN2 * x^2 + ... + SIN7 * x^12 + SIN8 * x^14 )
Packit 6c4009
   x in <0,0.1484375>  */
Packit 6c4009
#define SIN1 c[6]
Packit 6c4009
#define SIN2 c[7]
Packit 6c4009
#define SIN3 c[8]
Packit 6c4009
#define SIN4 c[9]
Packit 6c4009
#define SIN5 c[10]
Packit 6c4009
#define SIN6 c[11]
Packit 6c4009
#define SIN7 c[12]
Packit 6c4009
#define SIN8 c[13]
Packit 6c4009
-1.66666666666666666666666666666666538e-01L, /* bffc5555555555555555555555555550 */
Packit 6c4009
 8.33333333333333333333333333307532934e-03L, /* 3ff811111111111111111111110e7340 */
Packit 6c4009
-1.98412698412698412698412534478712057e-04L, /* bff2a01a01a01a01a01a019e7a626296 */
Packit 6c4009
 2.75573192239858906520896496653095890e-06L, /* 3fec71de3a556c7338fa38527474b8f5 */
Packit 6c4009
-2.50521083854417116999224301266655662e-08L, /* bfe5ae64567f544e16c7de65c2ea551f */
Packit 6c4009
 1.60590438367608957516841576404938118e-10L, /* 3fde6124613a811480538a9a41957115 */
Packit 6c4009
-7.64716343504264506714019494041582610e-13L, /* bfd6ae7f3d5aef30c7bc660b060ef365 */
Packit 6c4009
 2.81068754939739570236322404393398135e-15L, /* 3fce9510115aabf87aceb2022a9a9180 */
Packit 6c4009
Packit 6c4009
/* sin x ~ ONE * x + x^3 ( SSIN1 + SSIN2 * x^2 + ... + SSIN4 * x^6 + SSIN5 * x^8 )
Packit 6c4009
   x in <0,1/256>  */
Packit 6c4009
#define SSIN1 c[14]
Packit 6c4009
#define SSIN2 c[15]
Packit 6c4009
#define SSIN3 c[16]
Packit 6c4009
#define SSIN4 c[17]
Packit 6c4009
#define SSIN5 c[18]
Packit 6c4009
-1.66666666666666666666666666666666659E-01L, /* bffc5555555555555555555555555555 */
Packit 6c4009
 8.33333333333333333333333333146298442E-03L, /* 3ff81111111111111111111110fe195d */
Packit 6c4009
-1.98412698412698412697726277416810661E-04L, /* bff2a01a01a01a01a019e7121e080d88 */
Packit 6c4009
 2.75573192239848624174178393552189149E-06L, /* 3fec71de3a556c640c6aaa51aa02ab41 */
Packit 6c4009
-2.50521016467996193495359189395805639E-08L, /* bfe5ae644ee90c47dc71839de75b2787 */
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
#define SINCOSL_COS_HI 0
Packit 6c4009
#define SINCOSL_COS_LO 1
Packit 6c4009
#define SINCOSL_SIN_HI 2
Packit 6c4009
#define SINCOSL_SIN_LO 3
Packit 6c4009
extern const long double __sincosl_table[];
Packit 6c4009
Packit 6c4009
long double
Packit 6c4009
__kernel_sinl(long double x, long double y, int iy)
Packit 6c4009
{
Packit 6c4009
  long double h, l, z, sin_l, cos_l_m1;
Packit 6c4009
  int64_t ix;
Packit 6c4009
  uint32_t tix, hix, index;
Packit 6c4009
  double xhi, hhi;
Packit 6c4009
Packit 6c4009
  xhi = ldbl_high (x);
Packit 6c4009
  EXTRACT_WORDS64 (ix, xhi);
Packit 6c4009
  tix = ((uint64_t)ix) >> 32;
Packit 6c4009
  tix &= ~0x80000000;			/* tix = |x|'s high 32 bits */
Packit 6c4009
  if (tix < 0x3fc30000)			/* |x| < 0.1484375 */
Packit 6c4009
    {
Packit 6c4009
      /* Argument is small enough to approximate it by a Chebyshev
Packit 6c4009
	 polynomial of degree 17.  */
Packit 6c4009
      if (tix < 0x3c600000)		/* |x| < 2^-57 */
Packit 6c4009
	{
Packit 6c4009
	  math_check_force_underflow (x);
Packit 6c4009
	  if (!((int)x)) return x;	/* generate inexact */
Packit 6c4009
	}
Packit 6c4009
      z = x * x;
Packit 6c4009
      return x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+
Packit 6c4009
		       z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8)))))))));
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* So that we don't have to use too large polynomial,  we find
Packit 6c4009
	 l and h such that x = l + h,  where fabsl(l) <= 1.0/256 with 83
Packit 6c4009
	 possible values for h.  We look up cosl(h) and sinl(h) in
Packit 6c4009
	 pre-computed tables,  compute cosl(l) and sinl(l) using a
Packit 6c4009
	 Chebyshev polynomial of degree 10(11) and compute
Packit 6c4009
	 sinl(h+l) = sinl(h)cosl(l) + cosl(h)sinl(l).  */
Packit 6c4009
      int six = tix;
Packit 6c4009
      tix = ((six - 0x3ff00000) >> 4) + 0x3fff0000;
Packit 6c4009
      index = 0x3ffe - (tix >> 16);
Packit 6c4009
      hix = (tix + (0x200 << index)) & (0xfffffc00 << index);
Packit 6c4009
      x = fabsl (x);
Packit 6c4009
      switch (index)
Packit 6c4009
	{
Packit 6c4009
	case 0: index = ((45 << 10) + hix - 0x3ffe0000) >> 8; break;
Packit 6c4009
	case 1: index = ((13 << 11) + hix - 0x3ffd0000) >> 9; break;
Packit 6c4009
	default:
Packit 6c4009
	case 2: index = (hix - 0x3ffc3000) >> 10; break;
Packit 6c4009
	}
Packit 6c4009
      hix = (hix << 4) & 0x3fffffff;
Packit 6c4009
/*
Packit 6c4009
    The following should work for double but generates the wrong index.
Packit 6c4009
    For now the code above converts double to ieee extended to compute
Packit 6c4009
    the index back to double for the h value.
Packit 6c4009
Packit 6c4009
      index = 0x3fe - (tix >> 20);
Packit 6c4009
      hix = (tix + (0x2000 << index)) & (0xffffc000 << index);
Packit 6c4009
      x = fabsl (x);
Packit 6c4009
      switch (index)
Packit 6c4009
	{
Packit 6c4009
	case 0: index = ((45 << 14) + hix - 0x3fe00000) >> 12; break;
Packit 6c4009
	case 1: index = ((13 << 15) + hix - 0x3fd00000) >> 13; break;
Packit 6c4009
	default:
Packit 6c4009
	case 2: index = (hix - 0x3fc30000) >> 14; break;
Packit 6c4009
	}
Packit 6c4009
*/
Packit 6c4009
      INSERT_WORDS64 (hhi, ((uint64_t)hix) << 32);
Packit 6c4009
      h = hhi;
Packit 6c4009
      if (iy)
Packit 6c4009
	l = (ix < 0 ? -y : y) - (h - x);
Packit 6c4009
      else
Packit 6c4009
	l = x - h;
Packit 6c4009
      z = l * l;
Packit 6c4009
      sin_l = l*(ONE+z*(SSIN1+z*(SSIN2+z*(SSIN3+z*(SSIN4+z*SSIN5)))));
Packit 6c4009
      cos_l_m1 = z*(SCOS1+z*(SCOS2+z*(SCOS3+z*(SCOS4+z*SCOS5))));
Packit 6c4009
      z = __sincosl_table [index + SINCOSL_SIN_HI]
Packit 6c4009
	  + (__sincosl_table [index + SINCOSL_SIN_LO]
Packit 6c4009
	     + (__sincosl_table [index + SINCOSL_SIN_HI] * cos_l_m1)
Packit 6c4009
	     + (__sincosl_table [index + SINCOSL_COS_HI] * sin_l));
Packit 6c4009
      return (ix < 0) ? -z : z;
Packit 6c4009
    }
Packit 6c4009
}