From 4a42cebf6dd769e2fa4e234a9e91093b3ad1cb63 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sat, 12 Jun 2021 10:23:02 +0100 Subject: bpo-44339: Fix math.pow corner case to comply with IEEE 754 (GH-26606) Change the behaviour of `math.pow(0.0, -math.inf)` and `math.pow(-0.0, -math.inf)` to return positive infinity instead of raising `ValueError`. This makes `math.pow` consistent with the built-in `pow` (and the `**` operator) for this particular special case, and brings the `math.pow` special-case handling into compliance with IEEE 754. --- Doc/library/math.rst | 7 ++++++- Doc/whatsnew/3.11.rst | 10 ++++++++-- Lib/test/ieee754.txt | 6 ++---- Lib/test/test_math.py | 4 ++-- .../next/Library/2021-06-08-17-47-38.bpo-44339.9JwMSc.rst | 3 +++ Modules/mathmodule.c | 2 -- 6 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-06-08-17-47-38.bpo-44339.9JwMSc.rst diff --git a/Doc/library/math.rst b/Doc/library/math.rst index 7aa543a..7118678 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -409,7 +409,7 @@ Power and logarithmic functions .. function:: pow(x, y) Return ``x`` raised to the power ``y``. Exceptional cases follow - Annex 'F' of the C99 standard as far as possible. In particular, + the IEEE 754 standard as far as possible. In particular, ``pow(1.0, x)`` and ``pow(x, 0.0)`` always return ``1.0``, even when ``x`` is a zero or a NaN. If both ``x`` and ``y`` are finite, ``x`` is negative, and ``y`` is not an integer then ``pow(x, y)`` @@ -419,6 +419,11 @@ Power and logarithmic functions its arguments to type :class:`float`. Use ``**`` or the built-in :func:`pow` function for computing exact integer powers. + .. versionchanged:: 3.11 + The special cases ``pow(0.0, -inf)`` and ``pow(-0.0, -inf)`` were + changed to return ``inf`` instead of raising :exc:`ValueError`, + for consistency with IEEE 754. + .. function:: sqrt(x) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index ba7c456..50d91a0 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -96,8 +96,14 @@ string. (Contributed by Sergey B Kirpichev in :issue:`44258`.) math ---- -Add :func:`math.cbrt()`: return the cube root of x. -(Contributed by Ajith Ramachandran in :issue:`44357`.) +* Add :func:`math.cbrt`: return the cube root of x. + (Contributed by Ajith Ramachandran in :issue:`44357`.) + +* The behaviour of two :func:`math.pow` corner cases was changed, for + consistency with the IEEE 754 specification. The operations + ``math.pow(0.0, -math.inf)`` and ``math.pow(-0.0, -math.inf)`` now return + ``inf``. Previously they raised :exc:`ValueError`. (Contributed by Mark + Dickinson in :issue:`44339`.) Removed diff --git a/Lib/test/ieee754.txt b/Lib/test/ieee754.txt index 89bb0c5..a8b8a0a 100644 --- a/Lib/test/ieee754.txt +++ b/Lib/test/ieee754.txt @@ -104,7 +104,7 @@ infinity and NaN. 1.0 The power of 0 raised to x is defined as 0, if x is positive. Negative -values are a domain error or zero division error and NaN result in a +finite values are a domain error or zero division error and NaN result in a silent NaN. >>> pow(0, 0) @@ -112,9 +112,7 @@ silent NaN. >>> pow(0, INF) 0.0 >>> pow(0, -INF) -Traceback (most recent call last): -... -ValueError: math domain error +inf >>> 0 ** -1 Traceback (most recent call last): ... diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index da16284..42b61c3 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1230,7 +1230,7 @@ class MathTests(unittest.TestCase): self.assertRaises(ValueError, math.pow, 0., -2.) self.assertRaises(ValueError, math.pow, 0., -2.3) self.assertRaises(ValueError, math.pow, 0., -3.) - self.assertRaises(ValueError, math.pow, 0., NINF) + self.assertEqual(math.pow(0., NINF), INF) self.assertTrue(math.isnan(math.pow(0., NAN))) # pow(INF, x) @@ -1256,7 +1256,7 @@ class MathTests(unittest.TestCase): self.assertRaises(ValueError, math.pow, -0., -2.) self.assertRaises(ValueError, math.pow, -0., -2.3) self.assertRaises(ValueError, math.pow, -0., -3.) - self.assertRaises(ValueError, math.pow, -0., NINF) + self.assertEqual(math.pow(-0., NINF), INF) self.assertTrue(math.isnan(math.pow(-0., NAN))) # pow(NINF, x) diff --git a/Misc/NEWS.d/next/Library/2021-06-08-17-47-38.bpo-44339.9JwMSc.rst b/Misc/NEWS.d/next/Library/2021-06-08-17-47-38.bpo-44339.9JwMSc.rst new file mode 100644 index 0000000..10499eb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-06-08-17-47-38.bpo-44339.9JwMSc.rst @@ -0,0 +1,3 @@ +Change ``math.pow(±0.0, -math.inf)`` to return ``inf`` instead of raising +``ValueError``. This brings the special-case handling of ``math.pow`` into +compliance with the IEEE 754 standard. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index b3429c5..bd97b03 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2810,8 +2810,6 @@ math_pow_impl(PyObject *module, double x, double y) r = y; else if (y < 0. && fabs(x) < 1.0) { r = -y; /* result is +inf */ - if (x == 0.) /* 0**-inf: divide-by-zero */ - errno = EDOM; } else r = 0.; -- cgit v0.12