2006-01-28 00:15:15 +00:00
|
|
|
/*
|
|
|
|
* ====================================================
|
|
|
|
* 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
|
|
|
|
* software is freely granted, provided that this notice
|
|
|
|
* is preserved.
|
|
|
|
* ====================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Modifications for 128-bit long double are
|
|
|
|
Copyright (C) 2001 Stephen L. Moshier <moshier@na-net.ornl.gov>
|
|
|
|
and are incorporated herein by permission of the author. The author
|
|
|
|
reserves the right to distribute this material elsewhere under different
|
|
|
|
copying permissions. These modifications are distributed here under
|
|
|
|
the following terms:
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2012-02-09 23:18:22 +00:00
|
|
|
License along with this library; if not, see
|
|
|
|
<http://www.gnu.org/licenses/>. */
|
2006-01-28 00:15:15 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* __ieee754_jn(n, x), __ieee754_yn(n, x)
|
|
|
|
* floating point Bessel's function of the 1st and 2nd kind
|
|
|
|
* of order n
|
|
|
|
*
|
|
|
|
* Special cases:
|
|
|
|
* y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
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>
|
|
|
|
#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>
|
2006-01-28 00:15:15 +00:00
|
|
|
|
|
|
|
static const long double
|
|
|
|
invsqrtpi = 5.6418958354775628694807945156077258584405E-1L,
|
|
|
|
two = 2.0e0L,
|
|
|
|
one = 1.0e0L,
|
|
|
|
zero = 0.0L;
|
|
|
|
|
|
|
|
|
|
|
|
long double
|
|
|
|
__ieee754_jnl (int n, long double x)
|
|
|
|
{
|
2013-08-17 08:54:58 +00:00
|
|
|
uint32_t se, lx;
|
2006-01-28 00:15:15 +00:00
|
|
|
int32_t i, ix, 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
|
|
|
long double a, b, temp, di, ret;
|
2006-01-28 00:15:15 +00:00
|
|
|
long double z, w;
|
2013-08-17 08:54:58 +00:00
|
|
|
double xhi;
|
2006-01-28 00:15:15 +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)
|
|
|
|
*/
|
|
|
|
|
2013-08-17 08:54:58 +00:00
|
|
|
xhi = ldbl_high (x);
|
|
|
|
EXTRACT_WORDS (se, lx, xhi);
|
2006-01-28 00:15:15 +00:00
|
|
|
ix = se & 0x7fffffff;
|
|
|
|
|
|
|
|
/* if J(n,NaN) is NaN */
|
|
|
|
if (ix >= 0x7ff00000)
|
|
|
|
{
|
2013-08-17 08:54:58 +00:00
|
|
|
if (((ix - 0x7ff00000) | lx) != 0)
|
2006-01-28 00:15:15 +00:00
|
|
|
return x + x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n < 0)
|
|
|
|
{
|
|
|
|
n = -n;
|
|
|
|
x = -x;
|
|
|
|
se ^= 0x80000000;
|
|
|
|
}
|
|
|
|
if (n == 0)
|
|
|
|
return (__ieee754_j0l (x));
|
|
|
|
if (n == 1)
|
|
|
|
return (__ieee754_j1l (x));
|
|
|
|
sgn = (n & 1) & (se >> 31); /* even n -- 0, odd n -- sign(x) */
|
|
|
|
x = fabsl (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_ROUNDL (FE_TONEAREST);
|
|
|
|
if (x == 0.0L || ix >= 0x7ff00000) /* if x is 0 or inf */
|
|
|
|
return sgn == 1 ? -zero : zero;
|
|
|
|
else if ((long 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 */
|
2006-01-28 00:15:15 +00:00
|
|
|
|
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
|
|
|
/* ??? Could use an expansion for large x here. */
|
2006-01-28 00:15:15 +00:00
|
|
|
|
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
|
|
|
/* (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
|
|
|
|
*/
|
|
|
|
long double s;
|
|
|
|
long double c;
|
|
|
|
__sincosl (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;
|
|
|
|
}
|
2018-03-15 18:05:03 +00:00
|
|
|
b = invsqrtpi * temp / sqrtl (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_j0l (x);
|
|
|
|
b = __ieee754_j1l (x);
|
|
|
|
for (i = 1; i < n; i++)
|
|
|
|
{
|
|
|
|
temp = b;
|
|
|
|
b = b * ((long 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)
|
|
|
|
* J(n,x) = 1/n!*(x/2)^n - ...
|
|
|
|
*/
|
|
|
|
if (n >= 33) /* underflow, result < 10^-300 */
|
|
|
|
b = zero;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
temp = x * 0.5;
|
|
|
|
b = temp;
|
|
|
|
for (a = one, i = 2; i <= n; i++)
|
|
|
|
{
|
|
|
|
a *= (long 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 */
|
|
|
|
long double t, v;
|
|
|
|
long double q0, q1, h, tmp;
|
|
|
|
int32_t k, m;
|
|
|
|
w = (n + n) / (long double) x;
|
|
|
|
h = 2.0L / (long double) x;
|
|
|
|
q0 = w;
|
|
|
|
z = w + h;
|
|
|
|
q1 = w * z - 1.0L;
|
|
|
|
k = 1;
|
|
|
|
while (q1 < 1.0e17L)
|
|
|
|
{
|
|
|
|
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_logl (fabsl (v * tmp));
|
2006-01-28 00:15:15 +00:00
|
|
|
|
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 (tmp < 1.1356523406294143949491931077970765006170e+04L)
|
|
|
|
{
|
|
|
|
for (i = n - 1, di = (long double) (i + i); i > 0; i--)
|
|
|
|
{
|
|
|
|
temp = b;
|
|
|
|
b *= di;
|
|
|
|
b = b / x - a;
|
|
|
|
a = temp;
|
|
|
|
di -= two;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = n - 1, di = (long 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 > 1e100L)
|
|
|
|
{
|
|
|
|
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_j0l (x);
|
|
|
|
w = __ieee754_j1l (x);
|
|
|
|
if (fabsl (z) >= fabsl (w))
|
|
|
|
b = (t * z / b);
|
|
|
|
else
|
|
|
|
b = (t * w / a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sgn == 1)
|
|
|
|
ret = -b;
|
|
|
|
else
|
|
|
|
ret = b;
|
|
|
|
}
|
|
|
|
if (ret == 0)
|
2015-10-23 21:37:33 +00:00
|
|
|
{
|
2018-09-27 20:04:48 +00:00
|
|
|
ret = copysignl (LDBL_MIN, ret) * LDBL_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;
|
2006-01-28 00:15:15 +00:00
|
|
|
}
|
2011-10-23 13:20:16 +00:00
|
|
|
strong_alias (__ieee754_jnl, __jnl_finite)
|
2006-01-28 00:15:15 +00:00
|
|
|
|
|
|
|
long double
|
|
|
|
__ieee754_ynl (int n, long double x)
|
|
|
|
{
|
2013-08-17 08:54:58 +00:00
|
|
|
uint32_t se, lx;
|
2006-01-28 00:15:15 +00:00
|
|
|
int32_t i, ix;
|
|
|
|
int32_t sign;
|
2014-06-27 14:52:13 +00:00
|
|
|
long double a, b, temp, ret;
|
2013-08-17 08:54:58 +00:00
|
|
|
double xhi;
|
2006-01-28 00:15:15 +00:00
|
|
|
|
2013-08-17 08:54:58 +00:00
|
|
|
xhi = ldbl_high (x);
|
|
|
|
EXTRACT_WORDS (se, lx, xhi);
|
2006-01-28 00:15:15 +00:00
|
|
|
ix = se & 0x7fffffff;
|
|
|
|
|
|
|
|
/* if Y(n,NaN) is NaN */
|
|
|
|
if (ix >= 0x7ff00000)
|
|
|
|
{
|
2013-08-17 08:54:58 +00:00
|
|
|
if (((ix - 0x7ff00000) | lx) != 0)
|
2006-01-28 00:15:15 +00:00
|
|
|
return x + x;
|
|
|
|
}
|
|
|
|
if (x <= 0.0L)
|
|
|
|
{
|
|
|
|
if (x == 0.0L)
|
2013-12-04 14:39:37 +00:00
|
|
|
return ((n < 0 && (n & 1) != 0) ? 1.0L : -1.0L) / 0.0L;
|
2006-01-28 00:15:15 +00:00
|
|
|
if (se & 0x80000000)
|
|
|
|
return zero / (zero * x);
|
|
|
|
}
|
|
|
|
sign = 1;
|
|
|
|
if (n < 0)
|
|
|
|
{
|
|
|
|
n = -n;
|
|
|
|
sign = 1 - ((n & 1) << 1);
|
|
|
|
}
|
|
|
|
if (n == 0)
|
|
|
|
return (__ieee754_y0l (x));
|
2014-06-27 14:52:13 +00:00
|
|
|
{
|
|
|
|
SET_RESTORE_ROUNDL (FE_TONEAREST);
|
|
|
|
if (n == 1)
|
|
|
|
{
|
|
|
|
ret = sign * __ieee754_y1l (x);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (ix >= 0x7ff00000)
|
|
|
|
return zero;
|
|
|
|
if (ix >= 0x52D00000)
|
|
|
|
{ /* x > 2**302 */
|
2006-01-28 00:15:15 +00:00
|
|
|
|
2014-06-27 14:52:13 +00:00
|
|
|
/* ??? See comment above on the possible futility of this. */
|
2006-01-28 00:15:15 +00:00
|
|
|
|
2014-06-27 14:52:13 +00:00
|
|
|
/* (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
|
|
|
|
*/
|
|
|
|
long double s;
|
|
|
|
long double c;
|
|
|
|
__sincosl (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;
|
|
|
|
}
|
2018-03-15 18:05:03 +00:00
|
|
|
b = invsqrtpi * temp / sqrtl (x);
|
2014-06-27 14:52:13 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
a = __ieee754_y0l (x);
|
|
|
|
b = __ieee754_y1l (x);
|
|
|
|
/* quit if b is -inf */
|
|
|
|
xhi = ldbl_high (b);
|
|
|
|
GET_HIGH_WORD (se, xhi);
|
|
|
|
se &= 0xfff00000;
|
|
|
|
for (i = 1; i < n && se != 0xfff00000; i++)
|
|
|
|
{
|
|
|
|
temp = b;
|
|
|
|
b = ((long double) (i + i) / x) * b - a;
|
|
|
|
xhi = ldbl_high (b);
|
|
|
|
GET_HIGH_WORD (se, xhi);
|
|
|
|
se &= 0xfff00000;
|
|
|
|
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 = copysignl (LDBL_MAX, ret) * LDBL_MAX;
|
2014-06-27 14:52:13 +00:00
|
|
|
return ret;
|
2006-01-28 00:15:15 +00:00
|
|
|
}
|
2011-10-23 13:20:16 +00:00
|
|
|
strong_alias (__ieee754_ynl, __ynl_finite)
|