msvcrt: Import powf implementation from musl.
Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
9a459dc5af
commit
7bb574eafd
|
@ -1424,17 +1424,182 @@ float CDECL log10f( float x )
|
||||||
return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
|
return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subnormal input is normalized so ix has negative biased exponent.
|
||||||
|
Output is multiplied by POWF_SCALE (where 1 << 5). */
|
||||||
|
static double powf_log2(UINT32 ix)
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
double invc, logc;
|
||||||
|
} T[] = {
|
||||||
|
{ 0x1.661ec79f8f3bep+0, -0x1.efec65b963019p-2 * (1 << 5) },
|
||||||
|
{ 0x1.571ed4aaf883dp+0, -0x1.b0b6832d4fca4p-2 * (1 << 5) },
|
||||||
|
{ 0x1.49539f0f010bp+0, -0x1.7418b0a1fb77bp-2 * (1 << 5) },
|
||||||
|
{ 0x1.3c995b0b80385p+0, -0x1.39de91a6dcf7bp-2 * (1 << 5) },
|
||||||
|
{ 0x1.30d190c8864a5p+0, -0x1.01d9bf3f2b631p-2 * (1 << 5) },
|
||||||
|
{ 0x1.25e227b0b8eap+0, -0x1.97c1d1b3b7afp-3 * (1 << 5) },
|
||||||
|
{ 0x1.1bb4a4a1a343fp+0, -0x1.2f9e393af3c9fp-3 * (1 << 5) },
|
||||||
|
{ 0x1.12358f08ae5bap+0, -0x1.960cbbf788d5cp-4 * (1 << 5) },
|
||||||
|
{ 0x1.0953f419900a7p+0, -0x1.a6f9db6475fcep-5 * (1 << 5) },
|
||||||
|
{ 0x1p+0, 0x0p+0 * (1 << 4) },
|
||||||
|
{ 0x1.e608cfd9a47acp-1, 0x1.338ca9f24f53dp-4 * (1 << 5) },
|
||||||
|
{ 0x1.ca4b31f026aap-1, 0x1.476a9543891bap-3 * (1 << 5) },
|
||||||
|
{ 0x1.b2036576afce6p-1, 0x1.e840b4ac4e4d2p-3 * (1 << 5) },
|
||||||
|
{ 0x1.9c2d163a1aa2dp-1, 0x1.40645f0c6651cp-2 * (1 << 5) },
|
||||||
|
{ 0x1.886e6037841edp-1, 0x1.88e9c2c1b9ff8p-2 * (1 << 5) },
|
||||||
|
{ 0x1.767dcf5534862p-1, 0x1.ce0a44eb17bccp-2 * (1 << 5) }
|
||||||
|
};
|
||||||
|
static const double A[] = {
|
||||||
|
0x1.27616c9496e0bp-2 * (1 << 5), -0x1.71969a075c67ap-2 * (1 << 5),
|
||||||
|
0x1.ec70a6ca7baddp-2 * (1 << 5), -0x1.7154748bef6c8p-1 * (1 << 5),
|
||||||
|
0x1.71547652ab82bp0 * (1 << 5)
|
||||||
|
};
|
||||||
|
|
||||||
|
double z, r, r2, r4, p, q, y, y0, invc, logc;
|
||||||
|
UINT32 iz, top, tmp;
|
||||||
|
int k, i;
|
||||||
|
|
||||||
|
/* x = 2^k z; where z is in range [OFF,2*OFF] and exact.
|
||||||
|
The range is split into N subintervals.
|
||||||
|
The ith subinterval contains z and c is near its center. */
|
||||||
|
tmp = ix - 0x3f330000;
|
||||||
|
i = (tmp >> (23 - 4)) % (1 << 4);
|
||||||
|
top = tmp & 0xff800000;
|
||||||
|
iz = ix - top;
|
||||||
|
k = (INT32)top >> (23 - 5); /* arithmetic shift */
|
||||||
|
invc = T[i].invc;
|
||||||
|
logc = T[i].logc;
|
||||||
|
z = *(float*)&iz;
|
||||||
|
|
||||||
|
/* log2(x) = log1p(z/c-1)/ln2 + log2(c) + k */
|
||||||
|
r = z * invc - 1;
|
||||||
|
y0 = logc + (double)k;
|
||||||
|
|
||||||
|
/* Pipelined polynomial evaluation to approximate log1p(r)/ln2. */
|
||||||
|
r2 = r * r;
|
||||||
|
y = A[0] * r + A[1];
|
||||||
|
p = A[2] * r + A[3];
|
||||||
|
r4 = r2 * r2;
|
||||||
|
q = A[4] * r + y0;
|
||||||
|
q = p * r2 + q;
|
||||||
|
y = y * r4 + q;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The output of log2 and thus the input of exp2 is either scaled by N
|
||||||
|
(in case of fast toint intrinsics) or not. The unscaled xd must be
|
||||||
|
in [-1021,1023], sign_bias sets the sign of the result. */
|
||||||
|
static float powf_exp2(double xd, UINT32 sign_bias)
|
||||||
|
{
|
||||||
|
static const double C[] = {
|
||||||
|
0x1.c6af84b912394p-5 / (1 << 5) / (1 << 5) / (1 << 5),
|
||||||
|
0x1.ebfce50fac4f3p-3 / (1 << 5) / (1 << 5),
|
||||||
|
0x1.62e42ff0c52d6p-1 / (1 << 5)
|
||||||
|
};
|
||||||
|
|
||||||
|
UINT64 ki, ski, t;
|
||||||
|
double kd, z, r, r2, y, s;
|
||||||
|
|
||||||
|
/* N*x = k + r with r in [-1/2, 1/2] */
|
||||||
|
kd = __round(xd); /* k */
|
||||||
|
ki = kd;
|
||||||
|
r = xd - kd;
|
||||||
|
|
||||||
|
/* exp2(x) = 2^(k/N) * 2^r ~= s * (C0*r^3 + C1*r^2 + C2*r + 1) */
|
||||||
|
t = exp2f_T[ki % (1 << 5)];
|
||||||
|
ski = ki + sign_bias;
|
||||||
|
t += ski << (52 - 5);
|
||||||
|
s = *(double*)&t;
|
||||||
|
z = C[0] * r + C[1];
|
||||||
|
r2 = r * r;
|
||||||
|
y = C[2] * r + 1;
|
||||||
|
y = z * r2 + y;
|
||||||
|
y = y * s;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns 0 if not int, 1 if odd int, 2 if even int. The argument is
|
||||||
|
the bit representation of a non-zero finite floating-point value. */
|
||||||
|
static int powf_checkint(UINT32 iy)
|
||||||
|
{
|
||||||
|
int e = iy >> 23 & 0xff;
|
||||||
|
if (e < 0x7f)
|
||||||
|
return 0;
|
||||||
|
if (e > 0x7f + 23)
|
||||||
|
return 2;
|
||||||
|
if (iy & ((1 << (0x7f + 23 - e)) - 1))
|
||||||
|
return 0;
|
||||||
|
if (iy & (1 << (0x7f + 23 - e)))
|
||||||
|
return 1;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* powf (MSVCRT.@)
|
* powf (MSVCRT.@)
|
||||||
|
*
|
||||||
|
* Copied from musl: src/math/powf.c src/math/powf_data.c
|
||||||
*/
|
*/
|
||||||
float CDECL powf( float x, float y )
|
float CDECL powf( float x, float y )
|
||||||
{
|
{
|
||||||
float z = unix_funcs->powf(x,y);
|
UINT32 sign_bias = 0;
|
||||||
if (x < 0 && y != floorf(y)) return math_error(_DOMAIN, "powf", x, y, z);
|
UINT32 ix, iy;
|
||||||
if (!x && isfinite(y) && y < 0) return math_error(_SING, "powf", x, y, z);
|
double logx, ylogx;
|
||||||
if (isfinite(x) && isfinite(y) && !isfinite(z)) return math_error(_OVERFLOW, "powf", x, y, z);
|
|
||||||
if (x && isfinite(x) && isfinite(y) && !z) return math_error(_UNDERFLOW, "powf", x, y, z);
|
ix = *(UINT32*)&x;
|
||||||
return z;
|
iy = *(UINT32*)&y;
|
||||||
|
if (ix - 0x00800000 >= 0x7f800000 - 0x00800000 ||
|
||||||
|
2 * iy - 1 >= 2u * 0x7f800000 - 1) {
|
||||||
|
/* Either (x < 0x1p-126 or inf or nan) or (y is 0 or inf or nan). */
|
||||||
|
if (2 * iy - 1 >= 2u * 0x7f800000 - 1) {
|
||||||
|
if (2 * iy == 0)
|
||||||
|
return 1.0f;
|
||||||
|
if (ix == 0x3f800000)
|
||||||
|
return 1.0f;
|
||||||
|
if (2 * ix > 2u * 0x7f800000 || 2 * iy > 2u * 0x7f800000)
|
||||||
|
return x + y;
|
||||||
|
if (2 * ix == 2 * 0x3f800000)
|
||||||
|
return 1.0f;
|
||||||
|
if ((2 * ix < 2 * 0x3f800000) == !(iy & 0x80000000))
|
||||||
|
return 0.0f; /* |x|<1 && y==inf or |x|>1 && y==-inf. */
|
||||||
|
return y * y;
|
||||||
|
}
|
||||||
|
if (2 * ix - 1 >= 2u * 0x7f800000 - 1) {
|
||||||
|
float x2 = x * x;
|
||||||
|
if (ix & 0x80000000 && powf_checkint(iy) == 1)
|
||||||
|
x2 = -x2;
|
||||||
|
if (iy & 0x80000000 && x2 == 0.0)
|
||||||
|
return math_error(_SING, "powf", x, 0, 1 / x2);
|
||||||
|
/* Without the barrier some versions of clang hoist the 1/x2 and
|
||||||
|
thus division by zero exception can be signaled spuriously. */
|
||||||
|
return iy & 0x80000000 ? fp_barrierf(1 / x2) : x2;
|
||||||
|
}
|
||||||
|
/* x and y are non-zero finite. */
|
||||||
|
if (ix & 0x80000000) {
|
||||||
|
/* Finite x < 0. */
|
||||||
|
int yint = powf_checkint(iy);
|
||||||
|
if (yint == 0)
|
||||||
|
return math_error(_DOMAIN, "powf", x, 0, 0 / (x - x));
|
||||||
|
if (yint == 1)
|
||||||
|
sign_bias = 1 << (5 + 11);
|
||||||
|
ix &= 0x7fffffff;
|
||||||
|
}
|
||||||
|
if (ix < 0x00800000) {
|
||||||
|
/* Normalize subnormal x so exponent becomes negative. */
|
||||||
|
x *= 0x1p23f;
|
||||||
|
ix = *(UINT32*)&x;
|
||||||
|
ix &= 0x7fffffff;
|
||||||
|
ix -= 23 << 23;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logx = powf_log2(ix);
|
||||||
|
ylogx = y * logx; /* cannot overflow, y is single prec. */
|
||||||
|
if ((*(UINT64*)&ylogx >> 47 & 0xffff) >= 0x40af800000000000llu >> 47) {
|
||||||
|
/* |y*log(x)| >= 126. */
|
||||||
|
if (ylogx > 0x1.fffffffd1d571p+6 * (1 << 5))
|
||||||
|
return math_error(_OVERFLOW, "powf", x, 0, (sign_bias ? -1.0 : 1.0) * 0x1p1023);
|
||||||
|
if (ylogx <= -150.0 * (1 << 5))
|
||||||
|
return math_error(_UNDERFLOW, "powf", x, 0, (sign_bias ? -1.0 : 1.0) / 0x1p1023);
|
||||||
|
}
|
||||||
|
return powf_exp2(ylogx, sign_bias);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
|
|
|
@ -70,20 +70,11 @@ static double CDECL unix_pow( double x, double y )
|
||||||
return pow( x, y );
|
return pow( x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* powf
|
|
||||||
*/
|
|
||||||
static float CDECL unix_powf( float x, float y )
|
|
||||||
{
|
|
||||||
return powf( x, y );
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct unix_funcs funcs =
|
static const struct unix_funcs funcs =
|
||||||
{
|
{
|
||||||
unix_exp,
|
unix_exp,
|
||||||
unix_exp2,
|
unix_exp2,
|
||||||
unix_pow,
|
unix_pow,
|
||||||
unix_powf,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
|
NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
|
||||||
|
|
|
@ -26,7 +26,6 @@ struct unix_funcs
|
||||||
double (CDECL *exp)(double x);
|
double (CDECL *exp)(double x);
|
||||||
double (CDECL *exp2)(double x);
|
double (CDECL *exp2)(double x);
|
||||||
double (CDECL *pow)(double x, double y);
|
double (CDECL *pow)(double x, double y);
|
||||||
float (CDECL *powf)(float x, float y);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __UNIXLIB_H */
|
#endif /* __UNIXLIB_H */
|
||||||
|
|
Loading…
Reference in New Issue