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

Packit 6c4009
/*
Packit 6c4009
 * ====================================================
Packit 6c4009
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
Packit 6c4009
 *
Packit 6c4009
 * Developed at SunPro, a Sun Microsystems, Inc. business.
Packit 6c4009
 * Permission to use, copy, modify, and distribute this
Packit 6c4009
 * software is freely granted, provided that this notice
Packit 6c4009
 * is preserved.
Packit 6c4009
 * ====================================================
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
  Long double expansions are
Packit 6c4009
  Copyright (C) 2001 Stephen L. Moshier <moshier@na-net.ornl.gov>
Packit 6c4009
  and are incorporated herein by permission of the author.  The author
Packit 6c4009
  reserves the right to distribute this material elsewhere under different
Packit 6c4009
  copying permissions.  These modifications are distributed here under
Packit 6c4009
  the following terms:
Packit 6c4009
Packit 6c4009
    This 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
    This 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 this library; if not, see
Packit 6c4009
    <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* __kernel_tanl( x, y, k )
Packit 6c4009
 * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
Packit 6c4009
 * Input x is assumed to be bounded by ~pi/4 in magnitude.
Packit 6c4009
 * Input y is the tail of x.
Packit 6c4009
 * Input k indicates whether tan (if k=1) or
Packit 6c4009
 * -1/tan (if k= -1) is returned.
Packit 6c4009
 *
Packit 6c4009
 * Algorithm
Packit 6c4009
 *	1. Since tan(-x) = -tan(x), we need only to consider positive x.
Packit 6c4009
 *	2. if x < 2^-57, return x with inexact if x!=0.
Packit 6c4009
 *	3. tan(x) is approximated by a rational form x + x^3 / 3 + x^5 R(x^2)
Packit 6c4009
 *          on [0,0.67433].
Packit 6c4009
 *
Packit 6c4009
 *	   Note: tan(x+y) = tan(x) + tan'(x)*y
Packit 6c4009
 *		          ~ tan(x) + (1+x*x)*y
Packit 6c4009
 *	   Therefore, for better accuracy in computing tan(x+y), let
Packit 6c4009
 *		r = x^3 * R(x^2)
Packit 6c4009
 *	   then
Packit 6c4009
 *		tan(x+y) = x + (x^3 / 3 + (x^2 *(r+y)+y))
Packit 6c4009
 *
Packit 6c4009
 *      4. For x in [0.67433,pi/4],  let y = pi/4 - x, then
Packit 6c4009
 *		tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
Packit 6c4009
 *		       = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
Packit 6c4009
 */
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
#include <libc-diag.h>
Packit 6c4009
Packit 6c4009
static const long double
Packit 6c4009
  one = 1.0L,
Packit 6c4009
  pio4hi = 7.8539816339744830961566084581987569936977E-1L,
Packit 6c4009
  pio4lo = 2.1679525325309452561992610065108379921906E-35L,
Packit 6c4009
Packit 6c4009
  /* tan x = x + x^3 / 3 + x^5 T(x^2)/U(x^2)
Packit 6c4009
     0 <= x <= 0.6743316650390625
Packit 6c4009
     Peak relative error 8.0e-36  */
Packit 6c4009
 TH =  3.333333333333333333333333333333333333333E-1L,
Packit 6c4009
 T0 = -1.813014711743583437742363284336855889393E7L,
Packit 6c4009
 T1 =  1.320767960008972224312740075083259247618E6L,
Packit 6c4009
 T2 = -2.626775478255838182468651821863299023956E4L,
Packit 6c4009
 T3 =  1.764573356488504935415411383687150199315E2L,
Packit 6c4009
 T4 = -3.333267763822178690794678978979803526092E-1L,
Packit 6c4009
Packit 6c4009
 U0 = -1.359761033807687578306772463253710042010E8L,
Packit 6c4009
 U1 =  6.494370630656893175666729313065113194784E7L,
Packit 6c4009
 U2 = -4.180787672237927475505536849168729386782E6L,
Packit 6c4009
 U3 =  8.031643765106170040139966622980914621521E4L,
Packit 6c4009
 U4 = -5.323131271912475695157127875560667378597E2L;
Packit 6c4009
  /* 1.000000000000000000000000000000000000000E0 */
Packit 6c4009
Packit 6c4009
Packit 6c4009
long double
Packit 6c4009
__kernel_tanl (long double x, long double y, int iy)
Packit 6c4009
{
Packit 6c4009
  long double z, r, v, w, s;
Packit 6c4009
  int32_t ix, sign, hx, lx;
Packit 6c4009
  double xhi;
Packit 6c4009
Packit 6c4009
  xhi = ldbl_high (x);
Packit 6c4009
  EXTRACT_WORDS (hx, lx, xhi);
Packit 6c4009
  ix = hx & 0x7fffffff;
Packit 6c4009
  if (ix < 0x3c600000)		/* x < 2**-57 */
Packit 6c4009
    {
Packit 6c4009
      if ((int) x == 0)		/* generate inexact */
Packit 6c4009
	{
Packit 6c4009
	  if ((ix | lx | (iy + 1)) == 0)
Packit 6c4009
	    return one / fabs (x);
Packit 6c4009
	  else if (iy == 1)
Packit 6c4009
	    {
Packit 6c4009
	      math_check_force_underflow (x);
Packit 6c4009
	      return x;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    return -one / x;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  if (ix >= 0x3fe59420) /* |x| >= 0.6743316650390625 */
Packit 6c4009
    {
Packit 6c4009
      if ((hx & 0x80000000) != 0)
Packit 6c4009
	{
Packit 6c4009
	  x = -x;
Packit 6c4009
	  y = -y;
Packit 6c4009
	  sign = -1;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	sign = 1;
Packit 6c4009
      z = pio4hi - x;
Packit 6c4009
      w = pio4lo - y;
Packit 6c4009
      x = z + w;
Packit 6c4009
      y = 0.0;
Packit 6c4009
    }
Packit 6c4009
  z = x * x;
Packit 6c4009
  r = T0 + z * (T1 + z * (T2 + z * (T3 + z * T4)));
Packit 6c4009
  v = U0 + z * (U1 + z * (U2 + z * (U3 + z * (U4 + z))));
Packit 6c4009
  r = r / v;
Packit 6c4009
Packit 6c4009
  s = z * x;
Packit 6c4009
  r = y + z * (s * r + y);
Packit 6c4009
  r += TH * s;
Packit 6c4009
  w = x + r;
Packit 6c4009
  if (ix >= 0x3fe59420)
Packit 6c4009
    {
Packit 6c4009
      v = (long double) iy;
Packit 6c4009
      w = (v - 2.0 * (x - (w * w / (w + v) - r)));
Packit 6c4009
      /* SIGN is set for arguments that reach this code, but not
Packit 6c4009
	 otherwise, resulting in warnings that it may be used
Packit 6c4009
	 uninitialized although in the cases where it is used it has
Packit 6c4009
	 always been set.  */
Packit 6c4009
      DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
      DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
Packit 6c4009
      if (sign < 0)
Packit 6c4009
	w = -w;
Packit 6c4009
      DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
      return w;
Packit 6c4009
    }
Packit 6c4009
  if (iy == 1)
Packit 6c4009
    return w;
Packit 6c4009
  else
Packit 6c4009
    {				/* if allow error up to 2 ulp,
Packit 6c4009
				   simply return -1.0/(x+r) here */
Packit 6c4009
      /*  compute -1.0/(x+r) accurately */
Packit 6c4009
      long double u1, z1;
Packit 6c4009
Packit 6c4009
      u1 = ldbl_high (w);
Packit 6c4009
      v = r - (u1 - x);		/* u1+v = r+x */
Packit 6c4009
      z = -1.0 / w;
Packit 6c4009
      z1 = ldbl_high (z);
Packit 6c4009
      s = 1.0 + z1 * u1;
Packit 6c4009
      return z1 + z * (s + z1 * v);
Packit 6c4009
    }
Packit 6c4009
}