Commit 5c00be28 authored by Alexandre Julliard's avatar Alexandre Julliard

msvcrt: Use the tanh()/tanhf() implementation from the bundled musl library.

parent 4ffb1199
......@@ -496,7 +496,7 @@
@ varargs swscanf(wstr wstr)
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl tanh(double)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=win32 time(ptr) _time32
@ cdecl -arch=win64 time(ptr) _time64
@ cdecl tmpfile()
......
......@@ -1829,8 +1829,8 @@
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl -arch=!i386 tanf(float)
@ cdecl tanh(double)
@ cdecl -arch=!i386 tanhf(float)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=!i386 tanhf(float) MSVCRT_tanhf
@ cdecl tmpfile()
@ cdecl tmpfile_s(ptr)
@ cdecl tmpnam(ptr)
......
......@@ -2187,8 +2187,8 @@
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl -arch=!i386 tanf(float)
@ cdecl tanh(double)
@ cdecl -arch=!i386 tanhf(float)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=!i386 tanhf(float) MSVCRT_tanhf
@ cdecl tmpfile()
@ cdecl tmpfile_s(ptr)
@ cdecl tmpnam(ptr)
......
......@@ -2404,8 +2404,8 @@
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl -arch=!i386 tanf(float)
@ cdecl tanh(double)
@ cdecl -arch=!i386 tanhf(float)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=!i386 tanhf(float) MSVCRT_tanhf
@ cdecl tgamma(double)
@ cdecl tgammaf(float)
@ cdecl tgammal(double) tgamma
......
......@@ -844,7 +844,7 @@
@ varargs swscanf(wstr wstr)
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl tanh(double)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=win32 time(ptr) _time32
@ cdecl -arch=win64 time(ptr) _time64
@ cdecl tmpfile()
......
......@@ -839,7 +839,7 @@
@ varargs swscanf(wstr wstr)
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl tanh(double)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=win32 time(ptr) _time32
@ cdecl -arch=win64 time(ptr) _time64
@ cdecl tmpfile()
......
......@@ -1510,8 +1510,8 @@
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl -arch=!i386 tanf(float)
@ cdecl tanh(double)
@ cdecl -arch=!i386 tanhf(float)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=!i386 tanhf(float) MSVCRT_tanhf
@ cdecl tmpfile()
@ cdecl tmpfile_s(ptr)
@ cdecl tmpnam(ptr)
......
......@@ -1482,8 +1482,8 @@
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl -arch=!i386 tanf(float)
@ cdecl tanh(double)
@ cdecl -arch=!i386 tanhf(float)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=!i386 tanhf(float) MSVCRT_tanhf
@ cdecl tmpfile()
@ cdecl tmpfile_s(ptr)
@ cdecl tmpnam(ptr)
......
......@@ -78,19 +78,13 @@ void msvcrt_init_math( void *module )
}
/* Copied from musl: src/internal/libm.h */
#ifndef __i386__
static inline float fp_barrierf(float x)
{
volatile float y = x;
return y;
}
#endif
#if _MSVCR_VER >= 120
static inline double fp_barrier(double x)
{
volatile double y = x;
return y;
}
#endif
static inline double ret_nan( BOOL update_sw )
{
......@@ -399,49 +393,17 @@ float CDECL sqrtf( float x )
/*********************************************************************
* tanhf (MSVCRT.@)
*/
float CDECL tanhf( float x )
#if _MSVCR_VER < 140 /* other versions call tanhf() directly */
float CDECL MSVCRT_tanhf( float x )
{
UINT32 ui = *(UINT32*)&x;
UINT32 sign = ui & 0x80000000;
float t;
/* x = |x| */
ui &= 0x7fffffff;
x = *(float*)&ui;
if (ui > 0x3f0c9f54) {
/* |x| > log(3)/2 ~= 0.5493 or nan */
if (ui > 0x41200000) {
if (ui > 0x7f800000) {
*(UINT32*)&x = ui | sign | 0x400000;
#if _MSVCR_VER < 140
return math_error(_DOMAIN, "tanhf", x, 0, x);
#else
return x;
#endif
}
/* |x| > 10 */
fp_barrierf(x + 0x1p120f);
t = 1 + 0 / x;
} else {
t = expm1f(2 * x);
t = 1 - 2 / (t + 2);
}
} else if (ui > 0x3e82c578) {
/* |x| > log(5/3)/2 ~= 0.2554 */
t = expm1f(2 * x);
t = t / (t + 2);
} else if (ui >= 0x00800000) {
/* |x| >= 0x1p-126 */
t = expm1f(-2 * x);
t = -t / (t + 2);
} else {
/* |x| is subnormal */
fp_barrierf(x * x);
t = x;
}
return sign ? -t : t;
if (isnan( x ))
{
*(UINT32*)&x |= 0x400000;
return math_error(_DOMAIN, "tanhf", x, 0, x);
}
return tanhf( x );
}
#endif
#endif
......@@ -675,54 +637,17 @@ double CDECL sqrt( double x )
/*********************************************************************
* tanh (MSVCRT.@)
*/
double CDECL tanh( double x )
{
UINT64 ui = *(UINT64*)&x;
UINT64 sign = ui & 0x8000000000000000ULL;
UINT32 w;
double t;
/* x = |x| */
ui &= (UINT64)-1 / 2;
x = *(double*)&ui;
w = ui >> 32;
if (w > 0x3fe193ea) {
/* |x| > log(3)/2 ~= 0.5493 or nan */
if (w > 0x40340000) {
if (ui > 0x7ff0000000000000ULL) {
*(UINT64*)&x = ui | sign | 0x0008000000000000ULL;
#if _MSVCR_VER < 140
return math_error(_DOMAIN, "tanh", x, 0, x);
#else
return x;
#endif
}
/* |x| > 20 */
/* note: this branch avoids raising overflow */
fp_barrier(x + 0x1p120f);
t = 1 - 0 / x;
} else {
t = expm1(2 * x);
t = 1 - 2 / (t + 2);
}
} else if (w > 0x3fd058ae) {
/* |x| > log(5/3)/2 ~= 0.2554 */
t = expm1(2 * x);
t = t / (t + 2);
} else if (w >= 0x00100000) {
/* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */
t = expm1(-2 * x);
t = -t / (t + 2);
} else {
/* |x| is subnormal */
/* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */
fp_barrier((float)x);
t = x;
}
return sign ? -t : t;
#if _MSVCR_VER < 140 /* other versions call tanh() directly */
double CDECL MSVCRT_tanh( double x )
{
if (isnan( x ))
{
*(UINT64*)&x |= 0x0008000000000000ULL;
return math_error(_DOMAIN, "tanh", x, 0, x);
}
return tanh( x );
}
#endif
#if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
......
......@@ -1461,9 +1461,9 @@
@ varargs swscanf_s(wstr wstr)
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl tanh(double)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=!i386 tanf(float)
@ cdecl -arch=!i386 tanhf(float)
@ cdecl -arch=!i386 tanhf(float) MSVCRT_tanhf
@ cdecl -arch=win32 time(ptr) _time32
@ cdecl -arch=win64 time(ptr) _time64
@ cdecl tmpfile()
......
......@@ -797,7 +797,7 @@
@ varargs swscanf(wstr wstr)
@ cdecl system(str)
@ cdecl tan(double)
@ cdecl tanh(double)
@ cdecl tanh(double) MSVCRT_tanh
@ cdecl -arch=win32 time(ptr) _time32
@ cdecl -arch=win64 time(ptr) _time64
@ cdecl tmpfile()
......
......@@ -8,11 +8,11 @@ double __cdecl tanh(double x)
{
union {double f; uint64_t i;} u = {.f = x};
uint32_t w;
int sign;
uint64_t sign;
double_t t;
/* x = |x| */
sign = u.i >> 63;
sign = u.i & 0x8000000000000000ULL;
u.i &= (uint64_t)-1/2;
x = u.f;
w = u.i >> 32;
......@@ -20,8 +20,13 @@ double __cdecl tanh(double x)
if (w > 0x3fe193ea) {
/* |x| > log(3)/2 ~= 0.5493 or nan */
if (w > 0x40340000) {
if (w > 0x7ff00000) {
u.i |= sign | 0x0008000000000000ULL;
return u.f;
}
/* |x| > 20 or nan */
/* note: this branch avoids raising overflow */
fp_barrier(x + 0x1p120f);
t = 1 - 0/x;
} else {
t = expm1(2*x);
......
......@@ -4,11 +4,11 @@ float __cdecl tanhf(float x)
{
union {float f; uint32_t i;} u = {.f = x};
uint32_t w;
int sign;
uint32_t sign;
float t;
/* x = |x| */
sign = u.i >> 31;
sign = u.i & 0x80000000;
u.i &= 0x7fffffff;
x = u.f;
w = u.i;
......@@ -16,7 +16,12 @@ float __cdecl tanhf(float x)
if (w > 0x3f0c9f54) {
/* |x| > log(3)/2 ~= 0.5493 or nan */
if (w > 0x41200000) {
if (w > 0x7f800000) {
u.i |= sign | 0x400000;
return u.f;
}
/* |x| > 10 */
fp_barrierf(x + 0x1p120f);
t = 1 + 0/x;
} else {
t = expm1f(2*x);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment