diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index ba94a29800c871..ae3f5af0d47834 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -2765,12 +2765,6 @@ def test_fma_infinities(self): self.assertEqual(math.fma(-b, -math.inf, c), math.inf) self.assertEqual(math.fma(-b, math.inf, c), -math.inf) - # gh-73468: On some platforms, libc fma() doesn't implement IEE 754-2008 - # properly: it doesn't use the right sign when the result is zero. - @unittest.skipIf( - sys.platform.startswith(("freebsd", "wasi", "netbsd", "emscripten")) - or (sys.platform == "android" and platform.machine() == "x86_64"), - f"this platform doesn't implement IEE 754-2008 properly") def test_fma_zero_result(self): nonnegative_finites = [0.0, 1e-300, 2.3, 1e300] @@ -2812,6 +2806,13 @@ def test_fma_zero_result(self): self.assertIsPositiveZero(math.fma(-tiny, -tiny, -0.0)) self.assertIsNegativeZero(math.fma(-tiny, tiny, -0.0)) + # gh-73468: On some platforms, libc fma() doesn't implement IEE 754-2008 + # properly: it doesn't use the right sign when the result is zero. + @unittest.skipIf( + sys.platform.startswith(("freebsd", "netbsd", "emscripten")) + or (sys.platform == "android" and platform.machine() == "x86_64"), + f"this platform doesn't implement IEE 754-2008 properly") + def test_fma_zero_result2(self): # Corner case where rounding the multiplication would # give the wrong result. x = float.fromhex('0x1p-500') diff --git a/Misc/NEWS.d/next/Library/2025-03-12-08-14-54.gh-issue-131032.kpSzWI.rst b/Misc/NEWS.d/next/Library/2025-03-12-08-14-54.gh-issue-131032.kpSzWI.rst new file mode 100644 index 00000000000000..19644ec3f5b6b1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-12-08-14-54.gh-issue-131032.kpSzWI.rst @@ -0,0 +1,2 @@ +Fix :func:`math.fma(x, y, z) ` zero sign: fix the result sign when +*z* is zero. Patch by Victor Stinner and Sergey B Kirpichev. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index b4c15a143f9838..58fb04c268f5fc 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2344,7 +2344,20 @@ static PyObject * math_fma_impl(PyObject *module, double x, double y, double z) /*[clinic end generated code: output=4fc8626dbc278d17 input=e3ad1f4a4c89626e]*/ { - double r = fma(x, y, z); + double r; + if (z) { + r = fma(x, y, z); + } + else { + // gh-73468, gh-131032: On some platforms (ex: WASI, NetBSD, + // Emscripten, musl C library), libc fma() doesn't implement + // IEEE 754-2008 properly: it doesn't use the right sign when the + // result is zero. + r = x * y; + if ((!x || !y) && copysign(1, z) == 1) { + r += z; + } + } /* Fast path: if we got a finite result, we're done. */ if (isfinite(r)) {