1996-03-05 21:41:30 +00:00
|
|
|
/* @(#)e_jn.c 5.1 93/09/24 */
|
|
|
|
/*
|
|
|
|
* ====================================================
|
|
|
|
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
|
|
|
* Permission to use, copy, modify, and distribute this
|
2000-10-25 22:17:16 +00:00
|
|
|
* software is freely granted, provided that this notice
|
1996-03-05 21:41:30 +00:00
|
|
|
* is preserved.
|
|
|
|
* ====================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* __ieee754_jn(n, x), __ieee754_yn(n, x)
|
|
|
|
* floating point Bessel's function of the 1st and 2nd kind
|
|
|
|
* of order n
|
2000-10-25 22:17:16 +00:00
|
|
|
*
|
1996-03-05 21:41:30 +00:00
|
|
|
* Special cases:
|
2003-12-28 20:51:20 +00:00
|
|
|
* y0(0)=y1(0)=yn(n,0) = -inf with overflow signal;
|
1996-03-05 21:41:30 +00:00
|
|
|
* y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
|
|
|
|
* Note 2. About jn(n,x), yn(n,x)
|
|
|
|
* For n=0, j0(x) is called,
|
|
|
|
* for n=1, j1(x) is called,
|
|
|
|
* for n<x, forward recursion us used starting
|
|
|
|
* from values of j0(x) and j1(x).
|
|
|
|
* for n>x, a continued fraction approximation to
|
|
|
|
* j(n,x)/j(n-1,x) is evaluated and then backward
|
|
|
|
* recursion is used starting from a supposed value
|
|
|
|
* for j(n,x). The resulting value of j(0,x) is
|
|
|
|
* compared with the actual value to correct the
|
|
|
|
* supposed value of j(n,x).
|
|
|
|
*
|
|
|
|
* yn(n,x) is similar in all respects, except
|
|
|
|
* that forward recursion is used for all
|
|
|
|
* values of n>1.
|
2000-10-25 22:17:16 +00:00
|
|
|
*
|
1996-03-05 21:41:30 +00:00
|
|
|
*/
|
|
|
|
|
2012-07-25 10:59:36 +00:00
|
|
|
#include <errno.h>
|
2014-06-27 14:52:13 +00:00
|
|
|
#include <float.h>
|
2012-03-09 19:29:16 +00:00
|
|
|
#include <math.h>
|
2018-05-09 00:15:10 +00:00
|
|
|
#include <math-narrow-eval.h>
|
2012-03-09 19:29:16 +00:00
|
|
|
#include <math_private.h>
|
Do not include fenv_private.h in math_private.h.
Continuing the clean-up related to the catch-all math_private.h
header, this patch stops math_private.h from including fenv_private.h.
Instead, fenv_private.h is included directly from those users of
math_private.h that also used interfaces from fenv_private.h. No
attempt is made to remove unused includes of math_private.h, but that
is a natural followup.
(However, since math_private.h sometimes defines optimized versions of
math.h interfaces or __* variants thereof, as well as defining its own
interfaces, I think it might make sense to get all those optimized
versions included from include/math.h, not requiring a separate header
at all, before eliminating unused math_private.h includes - that
avoids a file quietly becoming less-optimized if someone adds a call
to one of those interfaces without restoring a math_private.h include
to that file.)
There is still a pitfall that if code uses plain fe* and __fe*
interfaces, but only includes fenv.h and not fenv_private.h or (before
this patch) math_private.h, it will compile on platforms with
exceptions and rounding modes but not get the optimized versions (and
possibly not compile) on platforms without exception and rounding mode
support, so making it easy to break the build for such platforms
accidentally.
I think it would be most natural to move the inlines / macros for fe*
and __fe* in the case of no exceptions and rounding modes into
include/fenv.h, so that all code including fenv.h with _ISOMAC not
defined automatically gets them. Then fenv_private.h would be purely
the header for the libc_fe*, SET_RESTORE_ROUND etc. internal
interfaces and the risk of breaking the build on other platforms than
the one you tested on because of a missing fenv_private.h include
would be much reduced (and there would be some unused fenv_private.h
includes to remove along with unused math_private.h includes).
Tested for x86_64 and x86, and tested with build-many-glibcs.py that
installed stripped shared libraries are unchanged by this patch.
* sysdeps/generic/math_private.h: Do not include <fenv_private.h>.
* math/fromfp.h: Include <fenv_private.h>.
* math/math-narrow.h: Likewise.
* math/s_cexp_template.c: Likewise.
* math/s_csin_template.c: Likewise.
* math/s_csinh_template.c: Likewise.
* math/s_ctan_template.c: Likewise.
* math/s_ctanh_template.c: Likewise.
* math/s_iseqsig_template.c: Likewise.
* math/w_acos_compat.c: Likewise.
* math/w_acosf_compat.c: Likewise.
* math/w_acosl_compat.c: Likewise.
* math/w_asin_compat.c: Likewise.
* math/w_asinf_compat.c: Likewise.
* math/w_asinl_compat.c: Likewise.
* math/w_ilogb_template.c: Likewise.
* math/w_j0_compat.c: Likewise.
* math/w_j0f_compat.c: Likewise.
* math/w_j0l_compat.c: Likewise.
* math/w_j1_compat.c: Likewise.
* math/w_j1f_compat.c: Likewise.
* math/w_j1l_compat.c: Likewise.
* math/w_jn_compat.c: Likewise.
* math/w_jnf_compat.c: Likewise.
* math/w_llogb_template.c: Likewise.
* math/w_log10_compat.c: Likewise.
* math/w_log10f_compat.c: Likewise.
* math/w_log10l_compat.c: Likewise.
* math/w_log2_compat.c: Likewise.
* math/w_log2f_compat.c: Likewise.
* math/w_log2l_compat.c: Likewise.
* math/w_log_compat.c: Likewise.
* math/w_logf_compat.c: Likewise.
* math/w_logl_compat.c: Likewise.
* sysdeps/aarch64/fpu/feholdexcpt.c: Likewise.
* sysdeps/aarch64/fpu/fesetround.c: Likewise.
* sysdeps/aarch64/fpu/fgetexcptflg.c: Likewise.
* sysdeps/aarch64/fpu/ftestexcept.c: Likewise.
* sysdeps/ieee754/dbl-64/e_atan2.c: Likewise.
* sysdeps/ieee754/dbl-64/e_exp.c: Likewise.
* sysdeps/ieee754/dbl-64/e_exp2.c: Likewise.
* sysdeps/ieee754/dbl-64/e_gamma_r.c: Likewise.
* sysdeps/ieee754/dbl-64/e_jn.c: Likewise.
* sysdeps/ieee754/dbl-64/e_pow.c: Likewise.
* sysdeps/ieee754/dbl-64/e_remainder.c: Likewise.
* sysdeps/ieee754/dbl-64/e_sqrt.c: Likewise.
* sysdeps/ieee754/dbl-64/gamma_product.c: Likewise.
* sysdeps/ieee754/dbl-64/lgamma_neg.c: Likewise.
* sysdeps/ieee754/dbl-64/s_atan.c: Likewise.
* sysdeps/ieee754/dbl-64/s_fma.c: Likewise.
* sysdeps/ieee754/dbl-64/s_fmaf.c: Likewise.
* sysdeps/ieee754/dbl-64/s_llrint.c: Likewise.
* sysdeps/ieee754/dbl-64/s_llround.c: Likewise.
* sysdeps/ieee754/dbl-64/s_lrint.c: Likewise.
* sysdeps/ieee754/dbl-64/s_lround.c: Likewise.
* sysdeps/ieee754/dbl-64/s_nearbyint.c: Likewise.
* sysdeps/ieee754/dbl-64/s_sin.c: Likewise.
* sysdeps/ieee754/dbl-64/s_sincos.c: Likewise.
* sysdeps/ieee754/dbl-64/s_tan.c: Likewise.
* sysdeps/ieee754/dbl-64/wordsize-64/s_lround.c: Likewise.
* sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c: Likewise.
* sysdeps/ieee754/dbl-64/x2y2m1.c: Likewise.
* sysdeps/ieee754/float128/float128_private.h: Likewise.
* sysdeps/ieee754/flt-32/e_gammaf_r.c: Likewise.
* sysdeps/ieee754/flt-32/e_j1f.c: Likewise.
* sysdeps/ieee754/flt-32/e_jnf.c: Likewise.
* sysdeps/ieee754/flt-32/lgamma_negf.c: Likewise.
* sysdeps/ieee754/flt-32/s_llrintf.c: Likewise.
* sysdeps/ieee754/flt-32/s_llroundf.c: Likewise.
* sysdeps/ieee754/flt-32/s_lrintf.c: Likewise.
* sysdeps/ieee754/flt-32/s_lroundf.c: Likewise.
* sysdeps/ieee754/flt-32/s_nearbyintf.c: Likewise.
* sysdeps/ieee754/k_standardl.c: Likewise.
* sysdeps/ieee754/ldbl-128/e_expl.c: Likewise.
* sysdeps/ieee754/ldbl-128/e_gammal_r.c: Likewise.
* sysdeps/ieee754/ldbl-128/e_j1l.c: Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c: Likewise.
* sysdeps/ieee754/ldbl-128/gamma_productl.c: Likewise.
* sysdeps/ieee754/ldbl-128/lgamma_negl.c: Likewise.
* sysdeps/ieee754/ldbl-128/s_fmal.c: Likewise.
* sysdeps/ieee754/ldbl-128/s_llrintl.c: Likewise.
* sysdeps/ieee754/ldbl-128/s_llroundl.c: Likewise.
* sysdeps/ieee754/ldbl-128/s_lrintl.c: Likewise.
* sysdeps/ieee754/ldbl-128/s_lroundl.c: Likewise.
* sysdeps/ieee754/ldbl-128/s_nearbyintl.c: Likewise.
* sysdeps/ieee754/ldbl-128/x2y2m1l.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_expl.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_gammal_r.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_j1l.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/lgamma_negl.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/s_fmal.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/s_llrintl.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/s_llroundl.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/s_lrintl.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/s_lroundl.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/s_rintl.c: Likewise.
* sysdeps/ieee754/ldbl-128ibm/x2y2m1l.c: Likewise.
* sysdeps/ieee754/ldbl-96/e_gammal_r.c: Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c: Likewise.
* sysdeps/ieee754/ldbl-96/gamma_productl.c: Likewise.
* sysdeps/ieee754/ldbl-96/lgamma_negl.c: Likewise.
* sysdeps/ieee754/ldbl-96/s_fma.c: Likewise.
* sysdeps/ieee754/ldbl-96/s_fmal.c: Likewise.
* sysdeps/ieee754/ldbl-96/s_llrintl.c: Likewise.
* sysdeps/ieee754/ldbl-96/s_llroundl.c: Likewise.
* sysdeps/ieee754/ldbl-96/s_lrintl.c: Likewise.
* sysdeps/ieee754/ldbl-96/s_lroundl.c: Likewise.
* sysdeps/ieee754/ldbl-96/x2y2m1l.c: Likewise.
* sysdeps/powerpc/fpu/e_sqrt.c: Likewise.
* sysdeps/powerpc/fpu/e_sqrtf.c: Likewise.
* sysdeps/riscv/rv64/rvd/s_ceil.c: Likewise.
* sysdeps/riscv/rv64/rvd/s_floor.c: Likewise.
* sysdeps/riscv/rv64/rvd/s_nearbyint.c: Likewise.
* sysdeps/riscv/rv64/rvd/s_round.c: Likewise.
* sysdeps/riscv/rv64/rvd/s_roundeven.c: Likewise.
* sysdeps/riscv/rv64/rvd/s_trunc.c: Likewise.
* sysdeps/riscv/rvd/s_finite.c: Likewise.
* sysdeps/riscv/rvd/s_fmax.c: Likewise.
* sysdeps/riscv/rvd/s_fmin.c: Likewise.
* sysdeps/riscv/rvd/s_fpclassify.c: Likewise.
* sysdeps/riscv/rvd/s_isinf.c: Likewise.
* sysdeps/riscv/rvd/s_isnan.c: Likewise.
* sysdeps/riscv/rvd/s_issignaling.c: Likewise.
* sysdeps/riscv/rvf/fegetround.c: Likewise.
* sysdeps/riscv/rvf/feholdexcpt.c: Likewise.
* sysdeps/riscv/rvf/fesetenv.c: Likewise.
* sysdeps/riscv/rvf/fesetround.c: Likewise.
* sysdeps/riscv/rvf/feupdateenv.c: Likewise.
* sysdeps/riscv/rvf/fgetexcptflg.c: Likewise.
* sysdeps/riscv/rvf/ftestexcept.c: Likewise.
* sysdeps/riscv/rvf/s_ceilf.c: Likewise.
* sysdeps/riscv/rvf/s_finitef.c: Likewise.
* sysdeps/riscv/rvf/s_floorf.c: Likewise.
* sysdeps/riscv/rvf/s_fmaxf.c: Likewise.
* sysdeps/riscv/rvf/s_fminf.c: Likewise.
* sysdeps/riscv/rvf/s_fpclassifyf.c: Likewise.
* sysdeps/riscv/rvf/s_isinff.c: Likewise.
* sysdeps/riscv/rvf/s_isnanf.c: Likewise.
* sysdeps/riscv/rvf/s_issignalingf.c: Likewise.
* sysdeps/riscv/rvf/s_nearbyintf.c: Likewise.
* sysdeps/riscv/rvf/s_roundevenf.c: Likewise.
* sysdeps/riscv/rvf/s_roundf.c: Likewise.
* sysdeps/riscv/rvf/s_truncf.c: Likewise.
2018-09-03 21:09:04 +00:00
|
|
|
#include <fenv_private.h>
|
2018-05-10 00:53:04 +00:00
|
|
|
#include <math-underflow.h>
|
2019-07-16 15:17:22 +00:00
|
|
|
#include <libm-alias-finite.h>
|
1996-03-05 21:41:30 +00:00
|
|
|
|
|
|
|
static const double
|
2013-10-17 14:03:24 +00:00
|
|
|
invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
|
|
|
|
two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
|
|
|
|
one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
|
1996-03-05 21:41:30 +00:00
|
|
|
|
2013-10-17 14:03:24 +00:00
|
|
|
static const double zero = 0.00000000000000000000e+00;
|
1996-03-05 21:41:30 +00:00
|
|
|
|
2011-10-12 15:27:51 +00:00
|
|
|
double
|
2013-10-17 14:03:24 +00:00
|
|
|
__ieee754_jn (int n, double x)
|
1996-03-05 21:41:30 +00:00
|
|
|
{
|
2013-10-17 14:03:24 +00:00
|
|
|
int32_t i, hx, ix, lx, sgn;
|
Use round-to-nearest internally in jn, test with ALL_RM_TEST (bug 18602).
Some existing jn tests, if run in non-default rounding modes, produce
errors above those accepted in glibc, which causes problems for moving
tests of jn to use ALL_RM_TEST. This patch makes jn set rounding
to-nearest internally, as was done for yn some time ago, then computes
the appropriate underflowing value for results that underflowed to
zero in to-nearest, and moves the tests to ALL_RM_TEST. It does
nothing about the general inaccuracy of Bessel function
implementations in glibc, though it should make jn more accurate on
average in non-default rounding modes through reduced error
accumulation. The recomputation of results that underflowed to zero
should as a side-effect fix some cases of bug 16559, where jn just
used an exact zero, but that is *not* the goal of this patch and other
cases of that bug remain unfixed.
(Most of the changes in the patch are reindentation to add new scopes
for SET_RESTORE_ROUND*.)
Tested for x86_64, x86, powerpc and mips64.
[BZ #16559]
[BZ #18602]
* sysdeps/ieee754/dbl-64/e_jn.c (__ieee754_jn): Set
round-to-nearest internally then recompute results that
underflowed to zero in the original rounding mode.
* sysdeps/ieee754/flt-32/e_jnf.c (__ieee754_jnf): Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_jnl): Likewise
* math/libm-test.inc (jn_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-25 21:46:02 +00:00
|
|
|
double a, b, temp, di, ret;
|
2013-10-17 14:03:24 +00:00
|
|
|
double z, w;
|
1996-03-05 21:41:30 +00:00
|
|
|
|
2013-10-17 14:03:24 +00:00
|
|
|
/* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
|
|
|
|
* Thus, J(-n,x) = J(n,-x)
|
|
|
|
*/
|
|
|
|
EXTRACT_WORDS (hx, lx, x);
|
|
|
|
ix = 0x7fffffff & hx;
|
|
|
|
/* if J(n,NaN) is NaN */
|
2017-08-03 19:55:04 +00:00
|
|
|
if (__glibc_unlikely ((ix | ((uint32_t) (lx | -lx)) >> 31) > 0x7ff00000))
|
2013-10-17 14:03:24 +00:00
|
|
|
return x + x;
|
|
|
|
if (n < 0)
|
|
|
|
{
|
|
|
|
n = -n;
|
|
|
|
x = -x;
|
|
|
|
hx ^= 0x80000000;
|
|
|
|
}
|
|
|
|
if (n == 0)
|
|
|
|
return (__ieee754_j0 (x));
|
|
|
|
if (n == 1)
|
|
|
|
return (__ieee754_j1 (x));
|
|
|
|
sgn = (n & 1) & (hx >> 31); /* even n -- 0, odd n -- sign(x) */
|
|
|
|
x = fabs (x);
|
Use round-to-nearest internally in jn, test with ALL_RM_TEST (bug 18602).
Some existing jn tests, if run in non-default rounding modes, produce
errors above those accepted in glibc, which causes problems for moving
tests of jn to use ALL_RM_TEST. This patch makes jn set rounding
to-nearest internally, as was done for yn some time ago, then computes
the appropriate underflowing value for results that underflowed to
zero in to-nearest, and moves the tests to ALL_RM_TEST. It does
nothing about the general inaccuracy of Bessel function
implementations in glibc, though it should make jn more accurate on
average in non-default rounding modes through reduced error
accumulation. The recomputation of results that underflowed to zero
should as a side-effect fix some cases of bug 16559, where jn just
used an exact zero, but that is *not* the goal of this patch and other
cases of that bug remain unfixed.
(Most of the changes in the patch are reindentation to add new scopes
for SET_RESTORE_ROUND*.)
Tested for x86_64, x86, powerpc and mips64.
[BZ #16559]
[BZ #18602]
* sysdeps/ieee754/dbl-64/e_jn.c (__ieee754_jn): Set
round-to-nearest internally then recompute results that
underflowed to zero in the original rounding mode.
* sysdeps/ieee754/flt-32/e_jnf.c (__ieee754_jnf): Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_jnl): Likewise
* math/libm-test.inc (jn_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-25 21:46:02 +00:00
|
|
|
{
|
|
|
|
SET_RESTORE_ROUND (FE_TONEAREST);
|
|
|
|
if (__glibc_unlikely ((ix | lx) == 0 || ix >= 0x7ff00000))
|
|
|
|
/* if x is 0 or inf */
|
|
|
|
return sgn == 1 ? -zero : zero;
|
|
|
|
else if ((double) n <= x)
|
|
|
|
{
|
|
|
|
/* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
|
|
|
|
if (ix >= 0x52D00000) /* x > 2**302 */
|
|
|
|
{ /* (x >> n**2)
|
2013-10-17 14:03:24 +00:00
|
|
|
* Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
|
|
|
|
* Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
|
|
|
|
* Let s=sin(x), c=cos(x),
|
|
|
|
* xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
|
|
|
|
*
|
|
|
|
* n sin(xn)*sqt2 cos(xn)*sqt2
|
|
|
|
* ----------------------------------
|
|
|
|
* 0 s-c c+s
|
|
|
|
* 1 -s-c -c+s
|
|
|
|
* 2 -s+c -c-s
|
|
|
|
* 3 s+c c-s
|
|
|
|
*/
|
Use round-to-nearest internally in jn, test with ALL_RM_TEST (bug 18602).
Some existing jn tests, if run in non-default rounding modes, produce
errors above those accepted in glibc, which causes problems for moving
tests of jn to use ALL_RM_TEST. This patch makes jn set rounding
to-nearest internally, as was done for yn some time ago, then computes
the appropriate underflowing value for results that underflowed to
zero in to-nearest, and moves the tests to ALL_RM_TEST. It does
nothing about the general inaccuracy of Bessel function
implementations in glibc, though it should make jn more accurate on
average in non-default rounding modes through reduced error
accumulation. The recomputation of results that underflowed to zero
should as a side-effect fix some cases of bug 16559, where jn just
used an exact zero, but that is *not* the goal of this patch and other
cases of that bug remain unfixed.
(Most of the changes in the patch are reindentation to add new scopes
for SET_RESTORE_ROUND*.)
Tested for x86_64, x86, powerpc and mips64.
[BZ #16559]
[BZ #18602]
* sysdeps/ieee754/dbl-64/e_jn.c (__ieee754_jn): Set
round-to-nearest internally then recompute results that
underflowed to zero in the original rounding mode.
* sysdeps/ieee754/flt-32/e_jnf.c (__ieee754_jnf): Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_jnl): Likewise
* math/libm-test.inc (jn_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-25 21:46:02 +00:00
|
|
|
double s;
|
|
|
|
double c;
|
|
|
|
__sincos (x, &s, &c);
|
|
|
|
switch (n & 3)
|
|
|
|
{
|
|
|
|
case 0: temp = c + s; break;
|
|
|
|
case 1: temp = -c + s; break;
|
|
|
|
case 2: temp = -c - s; break;
|
|
|
|
case 3: temp = c - s; break;
|
2019-01-04 16:17:48 +00:00
|
|
|
default: __builtin_unreachable ();
|
Use round-to-nearest internally in jn, test with ALL_RM_TEST (bug 18602).
Some existing jn tests, if run in non-default rounding modes, produce
errors above those accepted in glibc, which causes problems for moving
tests of jn to use ALL_RM_TEST. This patch makes jn set rounding
to-nearest internally, as was done for yn some time ago, then computes
the appropriate underflowing value for results that underflowed to
zero in to-nearest, and moves the tests to ALL_RM_TEST. It does
nothing about the general inaccuracy of Bessel function
implementations in glibc, though it should make jn more accurate on
average in non-default rounding modes through reduced error
accumulation. The recomputation of results that underflowed to zero
should as a side-effect fix some cases of bug 16559, where jn just
used an exact zero, but that is *not* the goal of this patch and other
cases of that bug remain unfixed.
(Most of the changes in the patch are reindentation to add new scopes
for SET_RESTORE_ROUND*.)
Tested for x86_64, x86, powerpc and mips64.
[BZ #16559]
[BZ #18602]
* sysdeps/ieee754/dbl-64/e_jn.c (__ieee754_jn): Set
round-to-nearest internally then recompute results that
underflowed to zero in the original rounding mode.
* sysdeps/ieee754/flt-32/e_jnf.c (__ieee754_jnf): Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_jnl): Likewise
* math/libm-test.inc (jn_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-25 21:46:02 +00:00
|
|
|
}
|
2018-03-15 18:05:03 +00:00
|
|
|
b = invsqrtpi * temp / sqrt (x);
|
Use round-to-nearest internally in jn, test with ALL_RM_TEST (bug 18602).
Some existing jn tests, if run in non-default rounding modes, produce
errors above those accepted in glibc, which causes problems for moving
tests of jn to use ALL_RM_TEST. This patch makes jn set rounding
to-nearest internally, as was done for yn some time ago, then computes
the appropriate underflowing value for results that underflowed to
zero in to-nearest, and moves the tests to ALL_RM_TEST. It does
nothing about the general inaccuracy of Bessel function
implementations in glibc, though it should make jn more accurate on
average in non-default rounding modes through reduced error
accumulation. The recomputation of results that underflowed to zero
should as a side-effect fix some cases of bug 16559, where jn just
used an exact zero, but that is *not* the goal of this patch and other
cases of that bug remain unfixed.
(Most of the changes in the patch are reindentation to add new scopes
for SET_RESTORE_ROUND*.)
Tested for x86_64, x86, powerpc and mips64.
[BZ #16559]
[BZ #18602]
* sysdeps/ieee754/dbl-64/e_jn.c (__ieee754_jn): Set
round-to-nearest internally then recompute results that
underflowed to zero in the original rounding mode.
* sysdeps/ieee754/flt-32/e_jnf.c (__ieee754_jnf): Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_jnl): Likewise
* math/libm-test.inc (jn_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-25 21:46:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
a = __ieee754_j0 (x);
|
|
|
|
b = __ieee754_j1 (x);
|
|
|
|
for (i = 1; i < n; i++)
|
|
|
|
{
|
|
|
|
temp = b;
|
|
|
|
b = b * ((double) (i + i) / x) - a; /* avoid underflow */
|
|
|
|
a = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ix < 0x3e100000) /* x < 2**-29 */
|
|
|
|
{ /* x is tiny, return the first Taylor expansion of J(n,x)
|
2013-10-17 14:03:24 +00:00
|
|
|
* J(n,x) = 1/n!*(x/2)^n - ...
|
|
|
|
*/
|
Use round-to-nearest internally in jn, test with ALL_RM_TEST (bug 18602).
Some existing jn tests, if run in non-default rounding modes, produce
errors above those accepted in glibc, which causes problems for moving
tests of jn to use ALL_RM_TEST. This patch makes jn set rounding
to-nearest internally, as was done for yn some time ago, then computes
the appropriate underflowing value for results that underflowed to
zero in to-nearest, and moves the tests to ALL_RM_TEST. It does
nothing about the general inaccuracy of Bessel function
implementations in glibc, though it should make jn more accurate on
average in non-default rounding modes through reduced error
accumulation. The recomputation of results that underflowed to zero
should as a side-effect fix some cases of bug 16559, where jn just
used an exact zero, but that is *not* the goal of this patch and other
cases of that bug remain unfixed.
(Most of the changes in the patch are reindentation to add new scopes
for SET_RESTORE_ROUND*.)
Tested for x86_64, x86, powerpc and mips64.
[BZ #16559]
[BZ #18602]
* sysdeps/ieee754/dbl-64/e_jn.c (__ieee754_jn): Set
round-to-nearest internally then recompute results that
underflowed to zero in the original rounding mode.
* sysdeps/ieee754/flt-32/e_jnf.c (__ieee754_jnf): Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_jnl): Likewise
* math/libm-test.inc (jn_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-25 21:46:02 +00:00
|
|
|
if (n > 33) /* underflow */
|
|
|
|
b = zero;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
temp = x * 0.5; b = temp;
|
|
|
|
for (a = one, i = 2; i <= n; i++)
|
|
|
|
{
|
|
|
|
a *= (double) i; /* a = n! */
|
|
|
|
b *= temp; /* b = (x/2)^n */
|
|
|
|
}
|
|
|
|
b = b / a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* use backward recurrence */
|
|
|
|
/* x x^2 x^2
|
|
|
|
* J(n,x)/J(n-1,x) = ---- ------ ------ .....
|
|
|
|
* 2n - 2(n+1) - 2(n+2)
|
|
|
|
*
|
|
|
|
* 1 1 1
|
|
|
|
* (for large x) = ---- ------ ------ .....
|
|
|
|
* 2n 2(n+1) 2(n+2)
|
|
|
|
* -- - ------ - ------ -
|
|
|
|
* x x x
|
|
|
|
*
|
|
|
|
* Let w = 2n/x and h=2/x, then the above quotient
|
|
|
|
* is equal to the continued fraction:
|
|
|
|
* 1
|
|
|
|
* = -----------------------
|
|
|
|
* 1
|
|
|
|
* w - -----------------
|
|
|
|
* 1
|
|
|
|
* w+h - ---------
|
|
|
|
* w+2h - ...
|
|
|
|
*
|
|
|
|
* To determine how many terms needed, let
|
|
|
|
* Q(0) = w, Q(1) = w(w+h) - 1,
|
|
|
|
* Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
|
|
|
|
* When Q(k) > 1e4 good for single
|
|
|
|
* When Q(k) > 1e9 good for double
|
|
|
|
* When Q(k) > 1e17 good for quadruple
|
|
|
|
*/
|
|
|
|
/* determine k */
|
|
|
|
double t, v;
|
|
|
|
double q0, q1, h, tmp; int32_t k, m;
|
|
|
|
w = (n + n) / (double) x; h = 2.0 / (double) x;
|
|
|
|
q0 = w; z = w + h; q1 = w * z - 1.0; k = 1;
|
|
|
|
while (q1 < 1.0e9)
|
|
|
|
{
|
|
|
|
k += 1; z += h;
|
|
|
|
tmp = z * q1 - q0;
|
|
|
|
q0 = q1;
|
|
|
|
q1 = tmp;
|
|
|
|
}
|
|
|
|
m = n + n;
|
|
|
|
for (t = zero, i = 2 * (n + k); i >= m; i -= 2)
|
|
|
|
t = one / (i / x - t);
|
|
|
|
a = t;
|
|
|
|
b = one;
|
|
|
|
/* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
|
|
|
|
* Hence, if n*(log(2n/x)) > ...
|
|
|
|
* single 8.8722839355e+01
|
|
|
|
* double 7.09782712893383973096e+02
|
|
|
|
* long double 1.1356523406294143949491931077970765006170e+04
|
|
|
|
* then recurrent value may overflow and the result is
|
|
|
|
* likely underflow to zero
|
|
|
|
*/
|
|
|
|
tmp = n;
|
|
|
|
v = two / x;
|
|
|
|
tmp = tmp * __ieee754_log (fabs (v * tmp));
|
|
|
|
if (tmp < 7.09782712893383973096e+02)
|
|
|
|
{
|
|
|
|
for (i = n - 1, di = (double) (i + i); i > 0; i--)
|
|
|
|
{
|
|
|
|
temp = b;
|
|
|
|
b *= di;
|
|
|
|
b = b / x - a;
|
|
|
|
a = temp;
|
|
|
|
di -= two;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = n - 1, di = (double) (i + i); i > 0; i--)
|
|
|
|
{
|
|
|
|
temp = b;
|
|
|
|
b *= di;
|
|
|
|
b = b / x - a;
|
|
|
|
a = temp;
|
|
|
|
di -= two;
|
|
|
|
/* scale b to avoid spurious overflow */
|
|
|
|
if (b > 1e100)
|
|
|
|
{
|
|
|
|
a /= b;
|
|
|
|
t /= b;
|
|
|
|
b = one;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* j0() and j1() suffer enormous loss of precision at and
|
|
|
|
* near zero; however, we know that their zero points never
|
|
|
|
* coincide, so just choose the one further away from zero.
|
|
|
|
*/
|
|
|
|
z = __ieee754_j0 (x);
|
|
|
|
w = __ieee754_j1 (x);
|
|
|
|
if (fabs (z) >= fabs (w))
|
|
|
|
b = (t * z / b);
|
|
|
|
else
|
|
|
|
b = (t * w / a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sgn == 1)
|
|
|
|
ret = -b;
|
|
|
|
else
|
|
|
|
ret = b;
|
2015-10-23 21:37:33 +00:00
|
|
|
ret = math_narrow_eval (ret);
|
Use round-to-nearest internally in jn, test with ALL_RM_TEST (bug 18602).
Some existing jn tests, if run in non-default rounding modes, produce
errors above those accepted in glibc, which causes problems for moving
tests of jn to use ALL_RM_TEST. This patch makes jn set rounding
to-nearest internally, as was done for yn some time ago, then computes
the appropriate underflowing value for results that underflowed to
zero in to-nearest, and moves the tests to ALL_RM_TEST. It does
nothing about the general inaccuracy of Bessel function
implementations in glibc, though it should make jn more accurate on
average in non-default rounding modes through reduced error
accumulation. The recomputation of results that underflowed to zero
should as a side-effect fix some cases of bug 16559, where jn just
used an exact zero, but that is *not* the goal of this patch and other
cases of that bug remain unfixed.
(Most of the changes in the patch are reindentation to add new scopes
for SET_RESTORE_ROUND*.)
Tested for x86_64, x86, powerpc and mips64.
[BZ #16559]
[BZ #18602]
* sysdeps/ieee754/dbl-64/e_jn.c (__ieee754_jn): Set
round-to-nearest internally then recompute results that
underflowed to zero in the original rounding mode.
* sysdeps/ieee754/flt-32/e_jnf.c (__ieee754_jnf): Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_jnl): Likewise
* math/libm-test.inc (jn_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-25 21:46:02 +00:00
|
|
|
}
|
|
|
|
if (ret == 0)
|
2015-10-23 21:37:33 +00:00
|
|
|
{
|
2018-09-27 20:04:48 +00:00
|
|
|
ret = math_narrow_eval (copysign (DBL_MIN, ret) * DBL_MIN);
|
2015-10-23 21:37:33 +00:00
|
|
|
__set_errno (ERANGE);
|
|
|
|
}
|
2015-09-23 22:42:30 +00:00
|
|
|
else
|
|
|
|
math_check_force_underflow (ret);
|
Use round-to-nearest internally in jn, test with ALL_RM_TEST (bug 18602).
Some existing jn tests, if run in non-default rounding modes, produce
errors above those accepted in glibc, which causes problems for moving
tests of jn to use ALL_RM_TEST. This patch makes jn set rounding
to-nearest internally, as was done for yn some time ago, then computes
the appropriate underflowing value for results that underflowed to
zero in to-nearest, and moves the tests to ALL_RM_TEST. It does
nothing about the general inaccuracy of Bessel function
implementations in glibc, though it should make jn more accurate on
average in non-default rounding modes through reduced error
accumulation. The recomputation of results that underflowed to zero
should as a side-effect fix some cases of bug 16559, where jn just
used an exact zero, but that is *not* the goal of this patch and other
cases of that bug remain unfixed.
(Most of the changes in the patch are reindentation to add new scopes
for SET_RESTORE_ROUND*.)
Tested for x86_64, x86, powerpc and mips64.
[BZ #16559]
[BZ #18602]
* sysdeps/ieee754/dbl-64/e_jn.c (__ieee754_jn): Set
round-to-nearest internally then recompute results that
underflowed to zero in the original rounding mode.
* sysdeps/ieee754/flt-32/e_jnf.c (__ieee754_jnf): Likewise.
* sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_jnl): Likewise.
* sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_jnl): Likewise
* math/libm-test.inc (jn_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-25 21:46:02 +00:00
|
|
|
return ret;
|
1996-03-05 21:41:30 +00:00
|
|
|
}
|
2019-07-16 15:17:22 +00:00
|
|
|
libm_alias_finite (__ieee754_jn, __jn)
|
1996-03-05 21:41:30 +00:00
|
|
|
|
2011-10-12 15:27:51 +00:00
|
|
|
double
|
2013-10-17 14:03:24 +00:00
|
|
|
__ieee754_yn (int n, double x)
|
1996-03-05 21:41:30 +00:00
|
|
|
{
|
2013-10-17 14:03:24 +00:00
|
|
|
int32_t i, hx, ix, lx;
|
|
|
|
int32_t sign;
|
2014-06-27 14:52:13 +00:00
|
|
|
double a, b, temp, ret;
|
1996-03-05 21:41:30 +00:00
|
|
|
|
2013-10-17 14:03:24 +00:00
|
|
|
EXTRACT_WORDS (hx, lx, x);
|
|
|
|
ix = 0x7fffffff & hx;
|
|
|
|
/* if Y(n,NaN) is NaN */
|
2017-08-03 19:55:04 +00:00
|
|
|
if (__glibc_unlikely ((ix | ((uint32_t) (lx | -lx)) >> 31) > 0x7ff00000))
|
2013-10-17 14:03:24 +00:00
|
|
|
return x + x;
|
|
|
|
sign = 1;
|
|
|
|
if (n < 0)
|
|
|
|
{
|
|
|
|
n = -n;
|
|
|
|
sign = 1 - ((n & 1) << 1);
|
|
|
|
}
|
|
|
|
if (n == 0)
|
|
|
|
return (__ieee754_y0 (x));
|
2017-10-03 17:12:42 +00:00
|
|
|
if (__glibc_unlikely ((ix | lx) == 0))
|
|
|
|
return -sign / zero;
|
|
|
|
/* -inf and overflow exception. */;
|
|
|
|
if (__glibc_unlikely (hx < 0))
|
|
|
|
return zero / (zero * x);
|
2014-06-27 14:52:13 +00:00
|
|
|
{
|
|
|
|
SET_RESTORE_ROUND (FE_TONEAREST);
|
|
|
|
if (n == 1)
|
|
|
|
{
|
|
|
|
ret = sign * __ieee754_y1 (x);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (__glibc_unlikely (ix == 0x7ff00000))
|
|
|
|
return zero;
|
|
|
|
if (ix >= 0x52D00000) /* x > 2**302 */
|
|
|
|
{ /* (x >> n**2)
|
|
|
|
* Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
|
|
|
|
* Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
|
|
|
|
* Let s=sin(x), c=cos(x),
|
|
|
|
* xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
|
|
|
|
*
|
|
|
|
* n sin(xn)*sqt2 cos(xn)*sqt2
|
|
|
|
* ----------------------------------
|
|
|
|
* 0 s-c c+s
|
|
|
|
* 1 -s-c -c+s
|
|
|
|
* 2 -s+c -c-s
|
|
|
|
* 3 s+c c-s
|
|
|
|
*/
|
|
|
|
double c;
|
|
|
|
double s;
|
|
|
|
__sincos (x, &s, &c);
|
|
|
|
switch (n & 3)
|
|
|
|
{
|
|
|
|
case 0: temp = s - c; break;
|
|
|
|
case 1: temp = -s - c; break;
|
|
|
|
case 2: temp = -s + c; break;
|
|
|
|
case 3: temp = s + c; break;
|
2019-01-04 16:17:48 +00:00
|
|
|
default: __builtin_unreachable ();
|
2014-06-27 14:52:13 +00:00
|
|
|
}
|
2018-03-15 18:05:03 +00:00
|
|
|
b = invsqrtpi * temp / sqrt (x);
|
2014-06-27 14:52:13 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-03 19:55:04 +00:00
|
|
|
uint32_t high;
|
2014-06-27 14:52:13 +00:00
|
|
|
a = __ieee754_y0 (x);
|
|
|
|
b = __ieee754_y1 (x);
|
|
|
|
/* quit if b is -inf */
|
|
|
|
GET_HIGH_WORD (high, b);
|
|
|
|
for (i = 1; i < n && high != 0xfff00000; i++)
|
|
|
|
{
|
|
|
|
temp = b;
|
|
|
|
b = ((double) (i + i) / x) * b - a;
|
|
|
|
GET_HIGH_WORD (high, b);
|
|
|
|
a = temp;
|
|
|
|
}
|
|
|
|
/* If B is +-Inf, set up errno accordingly. */
|
2015-06-03 14:36:34 +00:00
|
|
|
if (!isfinite (b))
|
2014-06-27 14:52:13 +00:00
|
|
|
__set_errno (ERANGE);
|
|
|
|
}
|
|
|
|
if (sign > 0)
|
|
|
|
ret = b;
|
|
|
|
else
|
|
|
|
ret = -b;
|
|
|
|
}
|
|
|
|
out:
|
2015-06-03 14:36:34 +00:00
|
|
|
if (isinf (ret))
|
2018-09-27 20:04:48 +00:00
|
|
|
ret = copysign (DBL_MAX, ret) * DBL_MAX;
|
2014-06-27 14:52:13 +00:00
|
|
|
return ret;
|
1996-03-05 21:41:30 +00:00
|
|
|
}
|
2019-07-16 15:17:22 +00:00
|
|
|
libm_alias_finite (__ieee754_yn, __yn)
|