This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Adjust thresholds in Bessel function implementations (bug 14469)
- From: Joseph Myers <joseph at codesourcery dot com>
- To: <libc-alpha at sourceware dot org>, <Paul dot Zimmermann at inria dot fr>
- Date: Thu, 13 Feb 2020 21:55:49 +0000
- Subject: Adjust thresholds in Bessel function implementations (bug 14469)
- Ironport-sdr: FijtigmU6fUyqDWxmEegPu5NpVIfnlMPM/fn7CGbNW8KawcwontI/9jBB4r1RDBWmCTNHrpkhO g6ti/WPT2RFw3Pt54duPc8INAziCJUdjDkJ+UES+6C9T334YH62kNSBfbBSrRC2yTto0KaYYLg u89+uHhxHnDdoiZAXOsSCdMhnJQ1VmfsTgeHq7HxaSmqul6cywImBFFncbjoKgXt7p95PqQPtM pHh9/VWrIoUEDlXDYIf2EuVixNIW5EH6HFA2q4Bs7rRgIqiEqQMPUcv24Kw8TYylIxXnghuPXM XUg=
- Ironport-sdr: u/wcGnCQtuHK2E/8ucy5BJIcIg3GV9GMmIBRA2Y7kYuH3GfoQfwWFswUuB6yQC5+zGyDfAsUkA vsQyBprGZ1PbAKlv+jVrGHXsFaY/4GuaH+APscadsgl/WWwhiIyldLPa1jv01KFojdk9qRp4yf 2EduR5Z0PwQEDNBPRA3YZQ1dD4AVdQD6vV1P0NU/+2Ci24GNsJVGCJJf24s+aNDu1W0/q5Q5Qy CbsCDMd+jBl1udJWvmph7uOZ8xTenI2+ESmEA6pzh1sq7Pl1kxyoJ38DKOwkB4Mf3Zl65j+ZRa umc=
A recent discussion in bug 14469 notes that a threshold in float
Bessel function implementations, used to determine when to use a
simpler implementation approach, results in substantially inaccurate
results.
As I discussed in
<https://sourceware.org/ml/libc-alpha/2013-03/msg00345.html>, a
heuristic argument suggests 2^(S+P) as the right order of magnitude
for a suitable threshold, where S is the number of significand bits in
the floating-point type and P is the number of significant bits in the
representation of the floating-point type, and the float and ldbl-96
implementations use thresholds that are too small. Some threshold
does need using, there or elsewhere in the implementation, to avoid
spurious underflow and overflow for large arguments.
This patch sets the thresholds in the affected implementations to more
heuristically justifiable values. Results will still be inaccurate
close to zeroes of the functions (thus this patch does *not* fix any
of the bugs for Bessel function inaccuracy); fixing that would require
a different implementation approach, likely along the lines described
in <http://www.cl.cam.ac.uk/~jrh13/papers/bessel.ps.gz>.
So the justification for a change such as thing would be statistical
rather than based on particular tests that had excessive errors and no
longer do so (no doubt such tests could be found, but would probably
be too fragile to add to the testsuite, as liable to give large errors
again from very small implementation changes or even from compiler
changes). Paul, could you run your exhaustive tests of j0f, j1f, y0f,
y1f with this patch and see what effect it has on the maximum ulp
error and the number of inputs with large errors?
Tested (glibc testsuite) for x86_64.
diff --git a/sysdeps/ieee754/flt-32/e_j0f.c b/sysdeps/ieee754/flt-32/e_j0f.c
index 0ac7d8e636..c89b9f2688 100644
--- a/sysdeps/ieee754/flt-32/e_j0f.c
+++ b/sysdeps/ieee754/flt-32/e_j0f.c
@@ -60,7 +60,7 @@ __ieee754_j0f(float x)
* j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
* y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
*/
- if(ix>0x48000000) z = (invsqrtpi*cc)/sqrtf(x);
+ if(ix>0x5c000000) z = (invsqrtpi*cc)/sqrtf(x);
else {
u = pzerof(x); v = qzerof(x);
z = invsqrtpi*(u*cc-v*ss)/sqrtf(x);
@@ -133,7 +133,7 @@ __ieee754_y0f(float x)
if ((s*c)<zero) cc = z/ss;
else ss = z/cc;
}
- if(ix>0x48000000) z = (invsqrtpi*ss)/sqrtf(x);
+ if(ix>0x5c000000) z = (invsqrtpi*ss)/sqrtf(x);
else {
u = pzerof(x); v = qzerof(x);
z = invsqrtpi*(u*ss+v*cc)/sqrtf(x);
diff --git a/sysdeps/ieee754/flt-32/e_j1f.c b/sysdeps/ieee754/flt-32/e_j1f.c
index eafff4f4b5..ac5bb76828 100644
--- a/sysdeps/ieee754/flt-32/e_j1f.c
+++ b/sysdeps/ieee754/flt-32/e_j1f.c
@@ -65,7 +65,7 @@ __ieee754_j1f(float x)
* j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
* y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
*/
- if(ix>0x48000000) z = (invsqrtpi*cc)/sqrtf(y);
+ if(ix>0x5c000000) z = (invsqrtpi*cc)/sqrtf(y);
else {
u = ponef(y); v = qonef(y);
z = invsqrtpi*(u*cc-v*ss)/sqrtf(y);
@@ -139,7 +139,7 @@ __ieee754_y1f(float x)
* sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
* to compute the worse one.
*/
- if(ix>0x48000000) z = (invsqrtpi*ss)/sqrtf(x);
+ if(ix>0x5c000000) z = (invsqrtpi*ss)/sqrtf(x);
else {
u = ponef(x); v = qonef(x);
z = invsqrtpi*(u*ss+v*cc)/sqrtf(x);
diff --git a/sysdeps/ieee754/ldbl-96/e_j0l.c b/sysdeps/ieee754/ldbl-96/e_j0l.c
index 715f56fb0b..d1f06c78e8 100644
--- a/sysdeps/ieee754/ldbl-96/e_j0l.c
+++ b/sysdeps/ieee754/ldbl-96/e_j0l.c
@@ -134,7 +134,7 @@ __ieee754_j0l (long double x)
* j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
* y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
*/
- if (__glibc_unlikely (ix > 0x4080)) /* 2^129 */
+ if (__glibc_unlikely (ix > 0x408e)) /* 2^143 */
z = (invsqrtpi * cc) / sqrtl (x);
else
{
@@ -236,7 +236,7 @@ __ieee754_y0l (long double x)
else
ss = z / cc;
}
- if (__glibc_unlikely (ix > 0x4080)) /* 1e39 */
+ if (__glibc_unlikely (ix > 0x408e)) /* 2^143 */
z = (invsqrtpi * ss) / sqrtl (x);
else
{
diff --git a/sysdeps/ieee754/ldbl-96/e_j1l.c b/sysdeps/ieee754/ldbl-96/e_j1l.c
index 2c967a6e56..b8ace5afd1 100644
--- a/sysdeps/ieee754/ldbl-96/e_j1l.c
+++ b/sysdeps/ieee754/ldbl-96/e_j1l.c
@@ -138,7 +138,7 @@ __ieee754_j1l (long double x)
* j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
* y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
*/
- if (__glibc_unlikely (ix > 0x4080))
+ if (__glibc_unlikely (ix > 0x408e))
z = (invsqrtpi * cc) / sqrtl (y);
else
{
@@ -232,7 +232,7 @@ __ieee754_y1l (long double x)
* sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
* to compute the worse one.
*/
- if (__glibc_unlikely (ix > 0x4080))
+ if (__glibc_unlikely (ix > 0x408e))
z = (invsqrtpi * ss) / sqrtl (x);
else
{
--
Joseph S. Myers
joseph@codesourcery.com