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

Packit Service 82fcde
/*
Packit Service 82fcde
 * ====================================================
Packit Service 82fcde
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
Packit Service 82fcde
 *
Packit Service 82fcde
 * Developed at SunPro, a Sun Microsystems, Inc. business.
Packit Service 82fcde
 * Permission to use, copy, modify, and distribute this
Packit Service 82fcde
 * software is freely granted, provided that this notice
Packit Service 82fcde
 * is preserved.
Packit Service 82fcde
 * ====================================================
Packit Service 82fcde
 */
Packit Service 82fcde
Packit Service 82fcde
/* Modifications for 128-bit long double are
Packit Service 82fcde
   Copyright (C) 2001 Stephen L. Moshier <moshier@na-net.ornl.gov>
Packit Service 82fcde
   and are incorporated herein by permission of the author.  The author
Packit Service 82fcde
   reserves the right to distribute this material elsewhere under different
Packit Service 82fcde
   copying permissions.  These modifications are distributed here under
Packit Service 82fcde
   the following terms:
Packit Service 82fcde
Packit Service 82fcde
    This library is free software; you can redistribute it and/or
Packit Service 82fcde
    modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
    License as published by the Free Software Foundation; either
Packit Service 82fcde
    version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
    This library is distributed in the hope that it will be useful,
Packit Service 82fcde
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
    Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
    You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
    License along with this library; if not, see
Packit Service 82fcde
    <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
/*
Packit Service 82fcde
 * __ieee754_jn(n, x), __ieee754_yn(n, x)
Packit Service 82fcde
 * floating point Bessel's function of the 1st and 2nd kind
Packit Service 82fcde
 * of order n
Packit Service 82fcde
 *
Packit Service 82fcde
 * Special cases:
Packit Service 82fcde
 *	y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
Packit Service 82fcde
 *	y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
Packit Service 82fcde
 * Note 2. About jn(n,x), yn(n,x)
Packit Service 82fcde
 *	For n=0, j0(x) is called,
Packit Service 82fcde
 *	for n=1, j1(x) is called,
Packit Service 82fcde
 *	for n
Packit Service 82fcde
 *	from values of j0(x) and j1(x).
Packit Service 82fcde
 *	for n>x, a continued fraction approximation to
Packit Service 82fcde
 *	j(n,x)/j(n-1,x) is evaluated and then backward
Packit Service 82fcde
 *	recursion is used starting from a supposed value
Packit Service 82fcde
 *	for j(n,x). The resulting value of j(0,x) is
Packit Service 82fcde
 *	compared with the actual value to correct the
Packit Service 82fcde
 *	supposed value of j(n,x).
Packit Service 82fcde
 *
Packit Service 82fcde
 *	yn(n,x) is similar in all respects, except
Packit Service 82fcde
 *	that forward recursion is used for all
Packit Service 82fcde
 *	values of n>1.
Packit Service 82fcde
 *
Packit Service 82fcde
 */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <float.h>
Packit Service 82fcde
#include <math.h>
Packit Service 82fcde
#include <math_private.h>
Packit Service 82fcde
#include <math-underflow.h>
Packit Service 82fcde
Packit Service 82fcde
static const long double
Packit Service 82fcde
  invsqrtpi = 5.6418958354775628694807945156077258584405E-1L,
Packit Service 82fcde
  two = 2.0e0L,
Packit Service 82fcde
  one = 1.0e0L,
Packit Service 82fcde
  zero = 0.0L;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
long double
Packit Service 82fcde
__ieee754_jnl (int n, long double x)
Packit Service 82fcde
{
Packit Service 82fcde
  uint32_t se, lx;
Packit Service 82fcde
  int32_t i, ix, sgn;
Packit Service 82fcde
  long double a, b, temp, di, ret;
Packit Service 82fcde
  long double z, w;
Packit Service 82fcde
  double xhi;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
  /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
Packit Service 82fcde
   * Thus, J(-n,x) = J(n,-x)
Packit Service 82fcde
   */
Packit Service 82fcde
Packit Service 82fcde
  xhi = ldbl_high (x);
Packit Service 82fcde
  EXTRACT_WORDS (se, lx, xhi);
Packit Service 82fcde
  ix = se & 0x7fffffff;
Packit Service 82fcde
Packit Service 82fcde
  /* if J(n,NaN) is NaN */
Packit Service 82fcde
  if (ix >= 0x7ff00000)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (((ix - 0x7ff00000) | lx) != 0)
Packit Service 82fcde
	return x + x;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (n < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      n = -n;
Packit Service 82fcde
      x = -x;
Packit Service 82fcde
      se ^= 0x80000000;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (n == 0)
Packit Service 82fcde
    return (__ieee754_j0l (x));
Packit Service 82fcde
  if (n == 1)
Packit Service 82fcde
    return (__ieee754_j1l (x));
Packit Service 82fcde
  sgn = (n & 1) & (se >> 31);	/* even n -- 0, odd n -- sign(x) */
Packit Service 82fcde
  x = fabsl (x);
Packit Service 82fcde
Packit Service 82fcde
  {
Packit Service 82fcde
    SET_RESTORE_ROUNDL (FE_TONEAREST);
Packit Service 82fcde
    if (x == 0.0L || ix >= 0x7ff00000)	/* if x is 0 or inf */
Packit Service 82fcde
      return sgn == 1 ? -zero : zero;
Packit Service 82fcde
    else if ((long double) n <= x)
Packit Service 82fcde
      {
Packit Service 82fcde
	/* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
Packit Service 82fcde
	if (ix >= 0x52d00000)
Packit Service 82fcde
	  {			/* x > 2**302 */
Packit Service 82fcde
Packit Service 82fcde
	    /* ??? Could use an expansion for large x here.  */
Packit Service 82fcde
Packit Service 82fcde
	    /* (x >> n**2)
Packit Service 82fcde
	     *      Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
Packit Service 82fcde
	     *      Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
Packit Service 82fcde
	     *      Let s=sin(x), c=cos(x),
Packit Service 82fcde
	     *          xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
Packit Service 82fcde
	     *
Packit Service 82fcde
	     *             n    sin(xn)*sqt2    cos(xn)*sqt2
Packit Service 82fcde
	     *          ----------------------------------
Packit Service 82fcde
	     *             0     s-c             c+s
Packit Service 82fcde
	     *             1    -s-c            -c+s
Packit Service 82fcde
	     *             2    -s+c            -c-s
Packit Service 82fcde
	     *             3     s+c             c-s
Packit Service 82fcde
	     */
Packit Service 82fcde
	    long double s;
Packit Service 82fcde
	    long double c;
Packit Service 82fcde
	    __sincosl (x, &s, &c);
Packit Service 82fcde
	    switch (n & 3)
Packit Service 82fcde
	      {
Packit Service 82fcde
	      case 0:
Packit Service 82fcde
		temp = c + s;
Packit Service 82fcde
		break;
Packit Service 82fcde
	      case 1:
Packit Service 82fcde
		temp = -c + s;
Packit Service 82fcde
		break;
Packit Service 82fcde
	      case 2:
Packit Service 82fcde
		temp = -c - s;
Packit Service 82fcde
		break;
Packit Service 82fcde
	      case 3:
Packit Service 82fcde
		temp = c - s;
Packit Service 82fcde
		break;
Packit Service 82fcde
	      }
Packit Service 82fcde
	    b = invsqrtpi * temp / sqrtl (x);
Packit Service 82fcde
	  }
Packit Service 82fcde
	else
Packit Service 82fcde
	  {
Packit Service 82fcde
	    a = __ieee754_j0l (x);
Packit Service 82fcde
	    b = __ieee754_j1l (x);
Packit Service 82fcde
	    for (i = 1; i < n; i++)
Packit Service 82fcde
	      {
Packit Service 82fcde
		temp = b;
Packit Service 82fcde
		b = b * ((long double) (i + i) / x) - a;	/* avoid underflow */
Packit Service 82fcde
		a = temp;
Packit Service 82fcde
	      }
Packit Service 82fcde
	  }
Packit Service 82fcde
      }
Packit Service 82fcde
    else
Packit Service 82fcde
      {
Packit Service 82fcde
	if (ix < 0x3e100000)
Packit Service 82fcde
	  {			/* x < 2**-29 */
Packit Service 82fcde
	    /* x is tiny, return the first Taylor expansion of J(n,x)
Packit Service 82fcde
	     * J(n,x) = 1/n!*(x/2)^n  - ...
Packit Service 82fcde
	     */
Packit Service 82fcde
	    if (n >= 33)		/* underflow, result < 10^-300 */
Packit Service 82fcde
	      b = zero;
Packit Service 82fcde
	    else
Packit Service 82fcde
	      {
Packit Service 82fcde
		temp = x * 0.5;
Packit Service 82fcde
		b = temp;
Packit Service 82fcde
		for (a = one, i = 2; i <= n; i++)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    a *= (long double) i;	/* a = n! */
Packit Service 82fcde
		    b *= temp;	/* b = (x/2)^n */
Packit Service 82fcde
		  }
Packit Service 82fcde
		b = b / a;
Packit Service 82fcde
	      }
Packit Service 82fcde
	  }
Packit Service 82fcde
	else
Packit Service 82fcde
	  {
Packit Service 82fcde
	    /* use backward recurrence */
Packit Service 82fcde
	    /*                      x      x^2      x^2
Packit Service 82fcde
	     *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
Packit Service 82fcde
	     *                      2n  - 2(n+1) - 2(n+2)
Packit Service 82fcde
	     *
Packit Service 82fcde
	     *                      1      1        1
Packit Service 82fcde
	     *  (for large x)   =  ----  ------   ------   .....
Packit Service 82fcde
	     *                      2n   2(n+1)   2(n+2)
Packit Service 82fcde
	     *                      -- - ------ - ------ -
Packit Service 82fcde
	     *                       x     x         x
Packit Service 82fcde
	     *
Packit Service 82fcde
	     * Let w = 2n/x and h=2/x, then the above quotient
Packit Service 82fcde
	     * is equal to the continued fraction:
Packit Service 82fcde
	     *                  1
Packit Service 82fcde
	     *      = -----------------------
Packit Service 82fcde
	     *                     1
Packit Service 82fcde
	     *         w - -----------------
Packit Service 82fcde
	     *                        1
Packit Service 82fcde
	     *              w+h - ---------
Packit Service 82fcde
	     *                     w+2h - ...
Packit Service 82fcde
	     *
Packit Service 82fcde
	     * To determine how many terms needed, let
Packit Service 82fcde
	     * Q(0) = w, Q(1) = w(w+h) - 1,
Packit Service 82fcde
	     * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
Packit Service 82fcde
	     * When Q(k) > 1e4      good for single
Packit Service 82fcde
	     * When Q(k) > 1e9      good for double
Packit Service 82fcde
	     * When Q(k) > 1e17     good for quadruple
Packit Service 82fcde
	     */
Packit Service 82fcde
	    /* determine k */
Packit Service 82fcde
	    long double t, v;
Packit Service 82fcde
	    long double q0, q1, h, tmp;
Packit Service 82fcde
	    int32_t k, m;
Packit Service 82fcde
	    w = (n + n) / (long double) x;
Packit Service 82fcde
	    h = 2.0L / (long double) x;
Packit Service 82fcde
	    q0 = w;
Packit Service 82fcde
	    z = w + h;
Packit Service 82fcde
	    q1 = w * z - 1.0L;
Packit Service 82fcde
	    k = 1;
Packit Service 82fcde
	    while (q1 < 1.0e17L)
Packit Service 82fcde
	      {
Packit Service 82fcde
		k += 1;
Packit Service 82fcde
		z += h;
Packit Service 82fcde
		tmp = z * q1 - q0;
Packit Service 82fcde
		q0 = q1;
Packit Service 82fcde
		q1 = tmp;
Packit Service 82fcde
	      }
Packit Service 82fcde
	    m = n + n;
Packit Service 82fcde
	    for (t = zero, i = 2 * (n + k); i >= m; i -= 2)
Packit Service 82fcde
	      t = one / (i / x - t);
Packit Service 82fcde
	    a = t;
Packit Service 82fcde
	    b = one;
Packit Service 82fcde
	    /*  estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
Packit Service 82fcde
	     *  Hence, if n*(log(2n/x)) > ...
Packit Service 82fcde
	     *  single 8.8722839355e+01
Packit Service 82fcde
	     *  double 7.09782712893383973096e+02
Packit Service 82fcde
	     *  long double 1.1356523406294143949491931077970765006170e+04
Packit Service 82fcde
	     *  then recurrent value may overflow and the result is
Packit Service 82fcde
	     *  likely underflow to zero
Packit Service 82fcde
	     */
Packit Service 82fcde
	    tmp = n;
Packit Service 82fcde
	    v = two / x;
Packit Service 82fcde
	    tmp = tmp * __ieee754_logl (fabsl (v * tmp));
Packit Service 82fcde
Packit Service 82fcde
	    if (tmp < 1.1356523406294143949491931077970765006170e+04L)
Packit Service 82fcde
	      {
Packit Service 82fcde
		for (i = n - 1, di = (long double) (i + i); i > 0; i--)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    temp = b;
Packit Service 82fcde
		    b *= di;
Packit Service 82fcde
		    b = b / x - a;
Packit Service 82fcde
		    a = temp;
Packit Service 82fcde
		    di -= two;
Packit Service 82fcde
		  }
Packit Service 82fcde
	      }
Packit Service 82fcde
	    else
Packit Service 82fcde
	      {
Packit Service 82fcde
		for (i = n - 1, di = (long double) (i + i); i > 0; i--)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    temp = b;
Packit Service 82fcde
		    b *= di;
Packit Service 82fcde
		    b = b / x - a;
Packit Service 82fcde
		    a = temp;
Packit Service 82fcde
		    di -= two;
Packit Service 82fcde
		    /* scale b to avoid spurious overflow */
Packit Service 82fcde
		    if (b > 1e100L)
Packit Service 82fcde
		      {
Packit Service 82fcde
			a /= b;
Packit Service 82fcde
			t /= b;
Packit Service 82fcde
			b = one;
Packit Service 82fcde
		      }
Packit Service 82fcde
		  }
Packit Service 82fcde
	      }
Packit Service 82fcde
	    /* j0() and j1() suffer enormous loss of precision at and
Packit Service 82fcde
	     * near zero; however, we know that their zero points never
Packit Service 82fcde
	     * coincide, so just choose the one further away from zero.
Packit Service 82fcde
	     */
Packit Service 82fcde
	    z = __ieee754_j0l (x);
Packit Service 82fcde
	    w = __ieee754_j1l (x);
Packit Service 82fcde
	    if (fabsl (z) >= fabsl (w))
Packit Service 82fcde
	      b = (t * z / b);
Packit Service 82fcde
	    else
Packit Service 82fcde
	      b = (t * w / a);
Packit Service 82fcde
	  }
Packit Service 82fcde
      }
Packit Service 82fcde
    if (sgn == 1)
Packit Service 82fcde
      ret = -b;
Packit Service 82fcde
    else
Packit Service 82fcde
      ret = b;
Packit Service 82fcde
  }
Packit Service 82fcde
  if (ret == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      ret = __copysignl (LDBL_MIN, ret) * LDBL_MIN;
Packit Service 82fcde
      __set_errno (ERANGE);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    math_check_force_underflow (ret);
Packit Service 82fcde
  return ret;
Packit Service 82fcde
}
Packit Service 82fcde
strong_alias (__ieee754_jnl, __jnl_finite)
Packit Service 82fcde
Packit Service 82fcde
long double
Packit Service 82fcde
__ieee754_ynl (int n, long double x)
Packit Service 82fcde
{
Packit Service 82fcde
  uint32_t se, lx;
Packit Service 82fcde
  int32_t i, ix;
Packit Service 82fcde
  int32_t sign;
Packit Service 82fcde
  long double a, b, temp, ret;
Packit Service 82fcde
  double xhi;
Packit Service 82fcde
Packit Service 82fcde
  xhi = ldbl_high (x);
Packit Service 82fcde
  EXTRACT_WORDS (se, lx, xhi);
Packit Service 82fcde
  ix = se & 0x7fffffff;
Packit Service 82fcde
Packit Service 82fcde
  /* if Y(n,NaN) is NaN */
Packit Service 82fcde
  if (ix >= 0x7ff00000)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (((ix - 0x7ff00000) | lx) != 0)
Packit Service 82fcde
	return x + x;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (x <= 0.0L)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (x == 0.0L)
Packit Service 82fcde
	return ((n < 0 && (n & 1) != 0) ? 1.0L : -1.0L) / 0.0L;
Packit Service 82fcde
      if (se & 0x80000000)
Packit Service 82fcde
	return zero / (zero * x);
Packit Service 82fcde
    }
Packit Service 82fcde
  sign = 1;
Packit Service 82fcde
  if (n < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      n = -n;
Packit Service 82fcde
      sign = 1 - ((n & 1) << 1);
Packit Service 82fcde
    }
Packit Service 82fcde
  if (n == 0)
Packit Service 82fcde
    return (__ieee754_y0l (x));
Packit Service 82fcde
  {
Packit Service 82fcde
    SET_RESTORE_ROUNDL (FE_TONEAREST);
Packit Service 82fcde
    if (n == 1)
Packit Service 82fcde
      {
Packit Service 82fcde
	ret = sign * __ieee754_y1l (x);
Packit Service 82fcde
	goto out;
Packit Service 82fcde
      }
Packit Service 82fcde
    if (ix >= 0x7ff00000)
Packit Service 82fcde
      return zero;
Packit Service 82fcde
    if (ix >= 0x52D00000)
Packit Service 82fcde
      {				/* x > 2**302 */
Packit Service 82fcde
Packit Service 82fcde
	/* ??? See comment above on the possible futility of this.  */
Packit Service 82fcde
Packit Service 82fcde
	/* (x >> n**2)
Packit Service 82fcde
	 *      Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
Packit Service 82fcde
	 *      Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
Packit Service 82fcde
	 *      Let s=sin(x), c=cos(x),
Packit Service 82fcde
	 *          xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
Packit Service 82fcde
	 *
Packit Service 82fcde
	 *             n    sin(xn)*sqt2    cos(xn)*sqt2
Packit Service 82fcde
	 *          ----------------------------------
Packit Service 82fcde
	 *             0     s-c             c+s
Packit Service 82fcde
	 *             1    -s-c            -c+s
Packit Service 82fcde
	 *             2    -s+c            -c-s
Packit Service 82fcde
	 *             3     s+c             c-s
Packit Service 82fcde
	 */
Packit Service 82fcde
	long double s;
Packit Service 82fcde
	long double c;
Packit Service 82fcde
	__sincosl (x, &s, &c);
Packit Service 82fcde
	switch (n & 3)
Packit Service 82fcde
	  {
Packit Service 82fcde
	  case 0:
Packit Service 82fcde
	    temp = s - c;
Packit Service 82fcde
	    break;
Packit Service 82fcde
	  case 1:
Packit Service 82fcde
	    temp = -s - c;
Packit Service 82fcde
	    break;
Packit Service 82fcde
	  case 2:
Packit Service 82fcde
	    temp = -s + c;
Packit Service 82fcde
	    break;
Packit Service 82fcde
	  case 3:
Packit Service 82fcde
	    temp = s + c;
Packit Service 82fcde
	    break;
Packit Service 82fcde
	  }
Packit Service 82fcde
	b = invsqrtpi * temp / sqrtl (x);
Packit Service 82fcde
      }
Packit Service 82fcde
    else
Packit Service 82fcde
      {
Packit Service 82fcde
	a = __ieee754_y0l (x);
Packit Service 82fcde
	b = __ieee754_y1l (x);
Packit Service 82fcde
	/* quit if b is -inf */
Packit Service 82fcde
	xhi = ldbl_high (b);
Packit Service 82fcde
	GET_HIGH_WORD (se, xhi);
Packit Service 82fcde
	se &= 0xfff00000;
Packit Service 82fcde
	for (i = 1; i < n && se != 0xfff00000; i++)
Packit Service 82fcde
	  {
Packit Service 82fcde
	    temp = b;
Packit Service 82fcde
	    b = ((long double) (i + i) / x) * b - a;
Packit Service 82fcde
	    xhi = ldbl_high (b);
Packit Service 82fcde
	    GET_HIGH_WORD (se, xhi);
Packit Service 82fcde
	    se &= 0xfff00000;
Packit Service 82fcde
	    a = temp;
Packit Service 82fcde
	  }
Packit Service 82fcde
      }
Packit Service 82fcde
    /* If B is +-Inf, set up errno accordingly.  */
Packit Service 82fcde
    if (! isfinite (b))
Packit Service 82fcde
      __set_errno (ERANGE);
Packit Service 82fcde
    if (sign > 0)
Packit Service 82fcde
      ret = b;
Packit Service 82fcde
    else
Packit Service 82fcde
      ret = -b;
Packit Service 82fcde
  }
Packit Service 82fcde
 out:
Packit Service 82fcde
  if (isinf (ret))
Packit Service 82fcde
    ret = __copysignl (LDBL_MAX, ret) * LDBL_MAX;
Packit Service 82fcde
  return ret;
Packit Service 82fcde
}
Packit Service 82fcde
strong_alias (__ieee754_ynl, __ynl_finite)