Blame sysdeps/ieee754/ldbl-128ibm/e_jnl.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
/* Modifications for 128-bit long double 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
/*
Packit 6c4009
 * __ieee754_jn(n, x), __ieee754_yn(n, x)
Packit 6c4009
 * floating point Bessel's function of the 1st and 2nd kind
Packit 6c4009
 * of order n
Packit 6c4009
 *
Packit 6c4009
 * Special cases:
Packit 6c4009
 *	y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
Packit 6c4009
 *	y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
Packit 6c4009
 * Note 2. About jn(n,x), yn(n,x)
Packit 6c4009
 *	For n=0, j0(x) is called,
Packit 6c4009
 *	for n=1, j1(x) is called,
Packit 6c4009
 *	for n
Packit 6c4009
 *	from values of j0(x) and j1(x).
Packit 6c4009
 *	for n>x, a continued fraction approximation to
Packit 6c4009
 *	j(n,x)/j(n-1,x) is evaluated and then backward
Packit 6c4009
 *	recursion is used starting from a supposed value
Packit 6c4009
 *	for j(n,x). The resulting value of j(0,x) is
Packit 6c4009
 *	compared with the actual value to correct the
Packit 6c4009
 *	supposed value of j(n,x).
Packit 6c4009
 *
Packit 6c4009
 *	yn(n,x) is similar in all respects, except
Packit 6c4009
 *	that forward recursion is used for all
Packit 6c4009
 *	values of n>1.
Packit 6c4009
 *
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <errno.h>
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
Packit 6c4009
  invsqrtpi = 5.6418958354775628694807945156077258584405E-1L,
Packit 6c4009
  two = 2.0e0L,
Packit 6c4009
  one = 1.0e0L,
Packit 6c4009
  zero = 0.0L;
Packit 6c4009
Packit 6c4009
Packit 6c4009
long double
Packit 6c4009
__ieee754_jnl (int n, long double x)
Packit 6c4009
{
Packit 6c4009
  uint32_t se, lx;
Packit 6c4009
  int32_t i, ix, sgn;
Packit 6c4009
  long double a, b, temp, di, ret;
Packit 6c4009
  long double z, w;
Packit 6c4009
  double xhi;
Packit 6c4009
Packit 6c4009
Packit 6c4009
  /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
Packit 6c4009
   * Thus, J(-n,x) = J(n,-x)
Packit 6c4009
   */
Packit 6c4009
Packit 6c4009
  xhi = ldbl_high (x);
Packit 6c4009
  EXTRACT_WORDS (se, lx, xhi);
Packit 6c4009
  ix = se & 0x7fffffff;
Packit 6c4009
Packit 6c4009
  /* if J(n,NaN) is NaN */
Packit 6c4009
  if (ix >= 0x7ff00000)
Packit 6c4009
    {
Packit 6c4009
      if (((ix - 0x7ff00000) | lx) != 0)
Packit 6c4009
	return x + x;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (n < 0)
Packit 6c4009
    {
Packit 6c4009
      n = -n;
Packit 6c4009
      x = -x;
Packit 6c4009
      se ^= 0x80000000;
Packit 6c4009
    }
Packit 6c4009
  if (n == 0)
Packit 6c4009
    return (__ieee754_j0l (x));
Packit 6c4009
  if (n == 1)
Packit 6c4009
    return (__ieee754_j1l (x));
Packit 6c4009
  sgn = (n & 1) & (se >> 31);	/* even n -- 0, odd n -- sign(x) */
Packit 6c4009
  x = fabsl (x);
Packit 6c4009
Packit 6c4009
  {
Packit 6c4009
    SET_RESTORE_ROUNDL (FE_TONEAREST);
Packit 6c4009
    if (x == 0.0L || ix >= 0x7ff00000)	/* if x is 0 or inf */
Packit 6c4009
      return sgn == 1 ? -zero : zero;
Packit 6c4009
    else if ((long double) n <= x)
Packit 6c4009
      {
Packit 6c4009
	/* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
Packit 6c4009
	if (ix >= 0x52d00000)
Packit 6c4009
	  {			/* x > 2**302 */
Packit 6c4009
Packit 6c4009
	    /* ??? Could use an expansion for large x here.  */
Packit 6c4009
Packit 6c4009
	    /* (x >> n**2)
Packit 6c4009
	     *      Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
Packit 6c4009
	     *      Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
Packit 6c4009
	     *      Let s=sin(x), c=cos(x),
Packit 6c4009
	     *          xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
Packit 6c4009
	     *
Packit 6c4009
	     *             n    sin(xn)*sqt2    cos(xn)*sqt2
Packit 6c4009
	     *          ----------------------------------
Packit 6c4009
	     *             0     s-c             c+s
Packit 6c4009
	     *             1    -s-c            -c+s
Packit 6c4009
	     *             2    -s+c            -c-s
Packit 6c4009
	     *             3     s+c             c-s
Packit 6c4009
	     */
Packit 6c4009
	    long double s;
Packit 6c4009
	    long double c;
Packit 6c4009
	    __sincosl (x, &s, &c);
Packit 6c4009
	    switch (n & 3)
Packit 6c4009
	      {
Packit 6c4009
	      case 0:
Packit 6c4009
		temp = c + s;
Packit 6c4009
		break;
Packit 6c4009
	      case 1:
Packit 6c4009
		temp = -c + s;
Packit 6c4009
		break;
Packit 6c4009
	      case 2:
Packit 6c4009
		temp = -c - s;
Packit 6c4009
		break;
Packit 6c4009
	      case 3:
Packit 6c4009
		temp = c - s;
Packit 6c4009
		break;
Packit 6c4009
	      }
Packit 6c4009
	    b = invsqrtpi * temp / sqrtl (x);
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
	  {
Packit 6c4009
	    a = __ieee754_j0l (x);
Packit 6c4009
	    b = __ieee754_j1l (x);
Packit 6c4009
	    for (i = 1; i < n; i++)
Packit 6c4009
	      {
Packit 6c4009
		temp = b;
Packit 6c4009
		b = b * ((long double) (i + i) / x) - a;	/* avoid underflow */
Packit 6c4009
		a = temp;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
    else
Packit 6c4009
      {
Packit 6c4009
	if (ix < 0x3e100000)
Packit 6c4009
	  {			/* x < 2**-29 */
Packit 6c4009
	    /* x is tiny, return the first Taylor expansion of J(n,x)
Packit 6c4009
	     * J(n,x) = 1/n!*(x/2)^n  - ...
Packit 6c4009
	     */
Packit 6c4009
	    if (n >= 33)		/* underflow, result < 10^-300 */
Packit 6c4009
	      b = zero;
Packit 6c4009
	    else
Packit 6c4009
	      {
Packit 6c4009
		temp = x * 0.5;
Packit 6c4009
		b = temp;
Packit 6c4009
		for (a = one, i = 2; i <= n; i++)
Packit 6c4009
		  {
Packit 6c4009
		    a *= (long double) i;	/* a = n! */
Packit 6c4009
		    b *= temp;	/* b = (x/2)^n */
Packit 6c4009
		  }
Packit 6c4009
		b = b / a;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
	  {
Packit 6c4009
	    /* use backward recurrence */
Packit 6c4009
	    /*                      x      x^2      x^2
Packit 6c4009
	     *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
Packit 6c4009
	     *                      2n  - 2(n+1) - 2(n+2)
Packit 6c4009
	     *
Packit 6c4009
	     *                      1      1        1
Packit 6c4009
	     *  (for large x)   =  ----  ------   ------   .....
Packit 6c4009
	     *                      2n   2(n+1)   2(n+2)
Packit 6c4009
	     *                      -- - ------ - ------ -
Packit 6c4009
	     *                       x     x         x
Packit 6c4009
	     *
Packit 6c4009
	     * Let w = 2n/x and h=2/x, then the above quotient
Packit 6c4009
	     * is equal to the continued fraction:
Packit 6c4009
	     *                  1
Packit 6c4009
	     *      = -----------------------
Packit 6c4009
	     *                     1
Packit 6c4009
	     *         w - -----------------
Packit 6c4009
	     *                        1
Packit 6c4009
	     *              w+h - ---------
Packit 6c4009
	     *                     w+2h - ...
Packit 6c4009
	     *
Packit 6c4009
	     * To determine how many terms needed, let
Packit 6c4009
	     * Q(0) = w, Q(1) = w(w+h) - 1,
Packit 6c4009
	     * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
Packit 6c4009
	     * When Q(k) > 1e4      good for single
Packit 6c4009
	     * When Q(k) > 1e9      good for double
Packit 6c4009
	     * When Q(k) > 1e17     good for quadruple
Packit 6c4009
	     */
Packit 6c4009
	    /* determine k */
Packit 6c4009
	    long double t, v;
Packit 6c4009
	    long double q0, q1, h, tmp;
Packit 6c4009
	    int32_t k, m;
Packit 6c4009
	    w = (n + n) / (long double) x;
Packit 6c4009
	    h = 2.0L / (long double) x;
Packit 6c4009
	    q0 = w;
Packit 6c4009
	    z = w + h;
Packit 6c4009
	    q1 = w * z - 1.0L;
Packit 6c4009
	    k = 1;
Packit 6c4009
	    while (q1 < 1.0e17L)
Packit 6c4009
	      {
Packit 6c4009
		k += 1;
Packit 6c4009
		z += h;
Packit 6c4009
		tmp = z * q1 - q0;
Packit 6c4009
		q0 = q1;
Packit 6c4009
		q1 = tmp;
Packit 6c4009
	      }
Packit 6c4009
	    m = n + n;
Packit 6c4009
	    for (t = zero, i = 2 * (n + k); i >= m; i -= 2)
Packit 6c4009
	      t = one / (i / x - t);
Packit 6c4009
	    a = t;
Packit 6c4009
	    b = one;
Packit 6c4009
	    /*  estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
Packit 6c4009
	     *  Hence, if n*(log(2n/x)) > ...
Packit 6c4009
	     *  single 8.8722839355e+01
Packit 6c4009
	     *  double 7.09782712893383973096e+02
Packit 6c4009
	     *  long double 1.1356523406294143949491931077970765006170e+04
Packit 6c4009
	     *  then recurrent value may overflow and the result is
Packit 6c4009
	     *  likely underflow to zero
Packit 6c4009
	     */
Packit 6c4009
	    tmp = n;
Packit 6c4009
	    v = two / x;
Packit 6c4009
	    tmp = tmp * __ieee754_logl (fabsl (v * tmp));
Packit 6c4009
Packit 6c4009
	    if (tmp < 1.1356523406294143949491931077970765006170e+04L)
Packit 6c4009
	      {
Packit 6c4009
		for (i = n - 1, di = (long double) (i + i); i > 0; i--)
Packit 6c4009
		  {
Packit 6c4009
		    temp = b;
Packit 6c4009
		    b *= di;
Packit 6c4009
		    b = b / x - a;
Packit 6c4009
		    a = temp;
Packit 6c4009
		    di -= two;
Packit 6c4009
		  }
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
	      {
Packit 6c4009
		for (i = n - 1, di = (long double) (i + i); i > 0; i--)
Packit 6c4009
		  {
Packit 6c4009
		    temp = b;
Packit 6c4009
		    b *= di;
Packit 6c4009
		    b = b / x - a;
Packit 6c4009
		    a = temp;
Packit 6c4009
		    di -= two;
Packit 6c4009
		    /* scale b to avoid spurious overflow */
Packit 6c4009
		    if (b > 1e100L)
Packit 6c4009
		      {
Packit 6c4009
			a /= b;
Packit 6c4009
			t /= b;
Packit 6c4009
			b = one;
Packit 6c4009
		      }
Packit 6c4009
		  }
Packit 6c4009
	      }
Packit 6c4009
	    /* j0() and j1() suffer enormous loss of precision at and
Packit 6c4009
	     * near zero; however, we know that their zero points never
Packit 6c4009
	     * coincide, so just choose the one further away from zero.
Packit 6c4009
	     */
Packit 6c4009
	    z = __ieee754_j0l (x);
Packit 6c4009
	    w = __ieee754_j1l (x);
Packit 6c4009
	    if (fabsl (z) >= fabsl (w))
Packit 6c4009
	      b = (t * z / b);
Packit 6c4009
	    else
Packit 6c4009
	      b = (t * w / a);
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
    if (sgn == 1)
Packit 6c4009
      ret = -b;
Packit 6c4009
    else
Packit 6c4009
      ret = b;
Packit 6c4009
  }
Packit 6c4009
  if (ret == 0)
Packit 6c4009
    {
Packit 6c4009
      ret = __copysignl (LDBL_MIN, ret) * LDBL_MIN;
Packit 6c4009
      __set_errno (ERANGE);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    math_check_force_underflow (ret);
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
strong_alias (__ieee754_jnl, __jnl_finite)
Packit 6c4009
Packit 6c4009
long double
Packit 6c4009
__ieee754_ynl (int n, long double x)
Packit 6c4009
{
Packit 6c4009
  uint32_t se, lx;
Packit 6c4009
  int32_t i, ix;
Packit 6c4009
  int32_t sign;
Packit 6c4009
  long double a, b, temp, ret;
Packit 6c4009
  double xhi;
Packit 6c4009
Packit 6c4009
  xhi = ldbl_high (x);
Packit 6c4009
  EXTRACT_WORDS (se, lx, xhi);
Packit 6c4009
  ix = se & 0x7fffffff;
Packit 6c4009
Packit 6c4009
  /* if Y(n,NaN) is NaN */
Packit 6c4009
  if (ix >= 0x7ff00000)
Packit 6c4009
    {
Packit 6c4009
      if (((ix - 0x7ff00000) | lx) != 0)
Packit 6c4009
	return x + x;
Packit 6c4009
    }
Packit 6c4009
  if (x <= 0.0L)
Packit 6c4009
    {
Packit 6c4009
      if (x == 0.0L)
Packit 6c4009
	return ((n < 0 && (n & 1) != 0) ? 1.0L : -1.0L) / 0.0L;
Packit 6c4009
      if (se & 0x80000000)
Packit 6c4009
	return zero / (zero * x);
Packit 6c4009
    }
Packit 6c4009
  sign = 1;
Packit 6c4009
  if (n < 0)
Packit 6c4009
    {
Packit 6c4009
      n = -n;
Packit 6c4009
      sign = 1 - ((n & 1) << 1);
Packit 6c4009
    }
Packit 6c4009
  if (n == 0)
Packit 6c4009
    return (__ieee754_y0l (x));
Packit 6c4009
  {
Packit 6c4009
    SET_RESTORE_ROUNDL (FE_TONEAREST);
Packit 6c4009
    if (n == 1)
Packit 6c4009
      {
Packit 6c4009
	ret = sign * __ieee754_y1l (x);
Packit 6c4009
	goto out;
Packit 6c4009
      }
Packit 6c4009
    if (ix >= 0x7ff00000)
Packit 6c4009
      return zero;
Packit 6c4009
    if (ix >= 0x52D00000)
Packit 6c4009
      {				/* x > 2**302 */
Packit 6c4009
Packit 6c4009
	/* ??? See comment above on the possible futility of this.  */
Packit 6c4009
Packit 6c4009
	/* (x >> n**2)
Packit 6c4009
	 *      Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
Packit 6c4009
	 *      Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
Packit 6c4009
	 *      Let s=sin(x), c=cos(x),
Packit 6c4009
	 *          xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
Packit 6c4009
	 *
Packit 6c4009
	 *             n    sin(xn)*sqt2    cos(xn)*sqt2
Packit 6c4009
	 *          ----------------------------------
Packit 6c4009
	 *             0     s-c             c+s
Packit 6c4009
	 *             1    -s-c            -c+s
Packit 6c4009
	 *             2    -s+c            -c-s
Packit 6c4009
	 *             3     s+c             c-s
Packit 6c4009
	 */
Packit 6c4009
	long double s;
Packit 6c4009
	long double c;
Packit 6c4009
	__sincosl (x, &s, &c);
Packit 6c4009
	switch (n & 3)
Packit 6c4009
	  {
Packit 6c4009
	  case 0:
Packit 6c4009
	    temp = s - c;
Packit 6c4009
	    break;
Packit 6c4009
	  case 1:
Packit 6c4009
	    temp = -s - c;
Packit 6c4009
	    break;
Packit 6c4009
	  case 2:
Packit 6c4009
	    temp = -s + c;
Packit 6c4009
	    break;
Packit 6c4009
	  case 3:
Packit 6c4009
	    temp = s + c;
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
	b = invsqrtpi * temp / sqrtl (x);
Packit 6c4009
      }
Packit 6c4009
    else
Packit 6c4009
      {
Packit 6c4009
	a = __ieee754_y0l (x);
Packit 6c4009
	b = __ieee754_y1l (x);
Packit 6c4009
	/* quit if b is -inf */
Packit 6c4009
	xhi = ldbl_high (b);
Packit 6c4009
	GET_HIGH_WORD (se, xhi);
Packit 6c4009
	se &= 0xfff00000;
Packit 6c4009
	for (i = 1; i < n && se != 0xfff00000; i++)
Packit 6c4009
	  {
Packit 6c4009
	    temp = b;
Packit 6c4009
	    b = ((long double) (i + i) / x) * b - a;
Packit 6c4009
	    xhi = ldbl_high (b);
Packit 6c4009
	    GET_HIGH_WORD (se, xhi);
Packit 6c4009
	    se &= 0xfff00000;
Packit 6c4009
	    a = temp;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
    /* If B is +-Inf, set up errno accordingly.  */
Packit 6c4009
    if (! isfinite (b))
Packit 6c4009
      __set_errno (ERANGE);
Packit 6c4009
    if (sign > 0)
Packit 6c4009
      ret = b;
Packit 6c4009
    else
Packit 6c4009
      ret = -b;
Packit 6c4009
  }
Packit 6c4009
 out:
Packit 6c4009
  if (isinf (ret))
Packit 6c4009
    ret = __copysignl (LDBL_MAX, ret) * LDBL_MAX;
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
strong_alias (__ieee754_ynl, __ynl_finite)