mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-132876: workaround broken ldexp() on Windows 10 (#133135)
* gh-132876: workaround broken ldexp() on Windows 10 ldexp() fails to round subnormal results before Windows 11, so hide their bug. Co-authored-by: Tim Peters <tim.peters@gmail.com>
This commit is contained in:
parent
0e3bc962c6
commit
cf8941c603
3 changed files with 31 additions and 0 deletions
|
@ -2161,6 +2161,27 @@ math_ldexp_impl(PyObject *module, double x, PyObject *i)
|
|||
} else {
|
||||
errno = 0;
|
||||
r = ldexp(x, (int)exp);
|
||||
#ifdef _MSC_VER
|
||||
if (DBL_MIN > r && r > -DBL_MIN) {
|
||||
/* Denormal (or zero) results can be incorrectly rounded here (rather,
|
||||
truncated). Fixed in newer versions of the C runtime, included
|
||||
with Windows 11. */
|
||||
int original_exp;
|
||||
frexp(x, &original_exp);
|
||||
if (original_exp > DBL_MIN_EXP) {
|
||||
/* Shift down to the smallest normal binade. No bits lost. */
|
||||
int shift = DBL_MIN_EXP - original_exp;
|
||||
x = ldexp(x, shift);
|
||||
exp -= shift;
|
||||
}
|
||||
/* Multiplying by 2**exp finishes the job, and the HW will round as
|
||||
appropriate. Note: if exp < -DBL_MANT_DIG, all of x is shifted
|
||||
to be < 0.5ULP of smallest denorm, so should be thrown away. If
|
||||
exp is so very negative that ldexp underflows to 0, that's fine;
|
||||
no need to check in advance. */
|
||||
r = x*ldexp(1.0, (int)exp);
|
||||
}
|
||||
#endif
|
||||
if (isinf(r))
|
||||
errno = ERANGE;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue