Hi, a similar issue happens with sinhf: $ cat test_sinh_musl.c #include <stdio.h> #include <stdlib.h> #include <math.h> int main () { float x = 0x1.62e4p+6; float y = sinhf (x); printf ("x=%a y=%a\n", x, y); } With GNU libc: $ gcc -fno-builtin test_sinh_musl.c -lm $ ./a.out x=0x1.62e4p+6 y=0x1.ffe808p+126 With musl-1.2.2: $ gcc -fno-builtin test_sinh_musl.c $FILES $ ./a.out x=0x1.62e4p+6 y=-nan Here we get NaN whereas the result is perfectly valid. Best regards, Paul
[-- Attachment #1: Type: text/plain, Size: 401 bytes --] * Paul Zimmermann <Paul.Zimmermann@inria.fr> [2021-02-05 09:01:09 +0100]: > $ cat test_sinh_musl.c > #include <stdio.h> > #include <stdlib.h> > #include <math.h> > > int > main () > { > float x = 0x1.62e4p+6; > float y = sinhf (x); > printf ("x=%a y=%a\n", x, y); > } ... > $ gcc -fno-builtin test_sinh_musl.c $FILES > $ ./a.out > x=0x1.62e4p+6 y=-nan this seems to be a bug, attaching a fix [-- Attachment #2: 0001-math-fix-acoshf-for-negative-inputs.patch --] [-- Type: text/x-diff, Size: 1641 bytes --] From 786b3725ff2f88a42a42c1c1fc98a34ef4c391ae Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy <nsz@port70.net> Date: Fri, 5 Feb 2021 18:48:19 +0000 Subject: [PATCH] math: fix acoshf for negative inputs on some negative inputs (e.g. -0x1.1e6ae8p+5) acoshf failed to return nan. ensure that negative inputs result nan without introducing new branches. this was tried before in commit 101e6012856918440b5d7474739c3fc22a8d3b85 math: fix acoshf on negative values but that fix was wrong. there are 3 formulas used: log1p(x-1 + sqrt((x-1)*(x-1)+2*(x-1))) log(2*x - 1/(x+sqrt(x*x-1))) log(x) + 0.693147180559945309417232121458176568 the first fails on large negative inputs (may compute log1p(0) or log1p(inf)), the second one fails on some mid range or large negative inputs (may compute log(large) or log(inf)) and the last one fails on -0 (returns -inf). --- src/math/acoshf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/math/acoshf.c b/src/math/acoshf.c index 8a4ec4d5..b773d48e 100644 --- a/src/math/acoshf.c +++ b/src/math/acoshf.c @@ -15,12 +15,12 @@ float acoshf(float x) uint32_t a = u.i & 0x7fffffff; if (a < 0x3f800000+(1<<23)) - /* |x| < 2, invalid if x < 1 or nan */ + /* |x| < 2, invalid if x < 1 */ /* up to 2ulp error in [1,1.125] */ return log1pf(x-1 + sqrtf((x-1)*(x-1)+2*(x-1))); - if (a < 0x3f800000+(12<<23)) - /* |x| < 0x1p12 */ + if (u.i < 0x3f800000+(12<<23)) + /* 2 <= x < 0x1p12 */ return logf(2*x - 1/(x+sqrtf(x*x-1))); - /* x >= 0x1p12 */ + /* x >= 0x1p12 or x <= -2 or nan */ return logf(x) + 0.693147180559945309417232121458176568f; } -- 2.29.2
[-- Attachment #1: Type: text/plain, Size: 704 bytes --] * Szabolcs Nagy <nsz@port70.net> [2021-02-05 21:09:34 +0100]: > * Paul Zimmermann <Paul.Zimmermann@inria.fr> [2021-02-05 09:01:09 +0100]: > > $ cat test_sinh_musl.c > > #include <stdio.h> > > #include <stdlib.h> > > #include <math.h> > > > > int > > main () > > { > > float x = 0x1.62e4p+6; > > float y = sinhf (x); > > printf ("x=%a y=%a\n", x, y); > > } > ... > > $ gcc -fno-builtin test_sinh_musl.c $FILES > > $ ./a.out > > x=0x1.62e4p+6 y=-nan > > this seems to be a bug, attaching a fix that one was for the acoshf bug, the sinhf issue was a bug in expm1f (overflowed too early, although sinhf could have used a less tight threshold that would have prevented this causing an issue there) [-- Attachment #2: 0001-math-fix-expm1f-overflow-threshold.patch --] [-- Type: text/x-diff, Size: 1126 bytes --] From 09f8837310082aeee019828b9aa805cf4528b3d1 Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy <nsz@port70.net> Date: Fri, 5 Feb 2021 19:51:36 +0000 Subject: [PATCH] math: fix expm1f overflow threshold the threshold was wrong so expm1f overflowed to inf a bit too early and on most targets uint32_t compare is faster than float compare so use that. this also fixes sinhf incorrectly returning nan for some values where the internal expm1f overflowed. --- src/math/expm1f.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/math/expm1f.c b/src/math/expm1f.c index 297e0b44..09a41afe 100644 --- a/src/math/expm1f.c +++ b/src/math/expm1f.c @@ -16,7 +16,6 @@ #include "libm.h" static const float -o_threshold = 8.8721679688e+01, /* 0x42b17180 */ ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ @@ -41,7 +40,7 @@ float expm1f(float x) return x; if (sign) return -1; - if (x > o_threshold) { + if (hx > 0x42b17217) { /* x > log(FLT_MAX) */ x *= 0x1p127f; return x; } -- 2.29.2
Dear Szabolcs,
> this seems to be a bug, attaching a fix
>
>
> [2:text/x-diff Show Save:0001-math-fix-acoshf-for-negative-inputs.patch (2kB)]
I confirm this solves the acoshf issue:
GNU libc:
$ gcc -fno-builtin test_acosh_musl.c -lm
$ ./a.out
x=-0x1.1e6ae8p+5 y=-nan
musl-1.2.2 + above patch:
$ gcc -fno-builtin test_acosh_musl.c $FILES
$ ./a.out
x=-0x1.1e6ae8p+5 y=-nan
Thank you!
Paul
Dear Szabolcs,
> that one was for the acoshf bug, the sinhf issue was a bug
> in expm1f (overflowed too early, although sinhf could have
> used a less tight threshold that would have prevented this
> causing an issue there)
>
>
> [2:text/x-diff Show Save:0001-math-fix-expm1f-overflow-threshold.patch (1kB)]
and that one fixes the sinhf issue:
GLIBC :
$ gcc -fno-builtin test_sinh_musl.c -lm
$ ./a.out
x=0x1.62e4p+6 y=0x1.ffe808p+126
musl-1.2.2 + above patch:
$ gcc -fno-builtin test_sinh_musl.c $FILES
$ ./a.out
x=0x1.62e4p+6 y=0x1.ffe808p+126
Thank you!
Paul