When a NAN is fed as input, return it as-is without mangling it through the calculation (which e.g. loses the sign of the input value).
This fixes a regression in a testcase of mine, after switching to the internal implementation of these functions.
Signed-off-by: Martin Storsjo martin@martin.st --- As these routines are imported from musl, I guess I should try to upstream the same fix to them too.
v2: Keep the math error reporting for msvcrt < 140 in tanh. --- dlls/msvcrt/math.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index ecf5fdce4d8..9b69f6bea56 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -1139,6 +1139,9 @@ float CDECL coshf( float x ) UINT32 ui = *(UINT32*)&x; float t;
+ if (isnan(x)) + return x; + /* |x| */ ui &= 0x7fffffff; x = *(float*)&ui; @@ -1676,6 +1679,9 @@ float CDECL sinhf( float x ) UINT32 ui = *(UINT32*)&x; float t, h, absx;
+ if (isnan(x)) + return x; + h = 0.5; if (ui >> 31) h = -h; @@ -1885,9 +1891,11 @@ float CDECL tanhf( float x ) if (ui > 0x3f0c9f54) { /* |x| > log(3)/2 ~= 0.5493 or nan */ if (ui > 0x41200000) { -#if _MSVCR_VER < 140 if (isnan(x)) +#if _MSVCR_VER < 140 return math_error(_DOMAIN, "tanhf", x, 0, x); +#else + return x; #endif /* |x| > 10 */ fp_barrierf(x + 0x1p120f); @@ -2769,6 +2777,9 @@ double CDECL cosh( double x ) UINT32 w; double t;
+ if (isnan(x)) + return x; + /* |x| */ ux &= (uint64_t)-1 / 2; x = *(double*)&ux; @@ -4035,6 +4046,9 @@ double CDECL sinh( double x ) UINT32 w; double t, h, absx;
+ if (isnan(x)) + return x; + h = 0.5; if (ux >> 63) h = -h; @@ -4331,9 +4345,11 @@ double CDECL tanh( double x ) if (w > 0x3fe193ea) { /* |x| > log(3)/2 ~= 0.5493 or nan */ if (w > 0x40340000) { -#if _MSVCR_VER < 140 if (isnan(x)) +#if _MSVCR_VER < 140 return math_error(_DOMAIN, "tanh", x, 0, x); +#else + return x; #endif /* |x| > 20 or nan */ /* note: this branch avoids raising overflow */