Skip to content

Commit 85ead4f

Browse files
authored
bpo-39396: Fix math.nextafter(-0.0, +0.0) on AIX 7.1 (GH-18094)
Move also math.nextafter() on math.ulp() tests from IsCloseTests to MathTests.
1 parent ec64640 commit 85ead4f

File tree

3 files changed

+86
-79
lines changed

3 files changed

+86
-79
lines changed

Lib/test/test_math.py

Lines changed: 77 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1752,6 +1752,83 @@ def assertIsNaN(self, value):
17521752
if not math.isnan(value):
17531753
self.fail("Expected a NaN, got {!r}.".format(value))
17541754

1755+
def assertEqualSign(self, x, y):
1756+
"""Similar to assertEqual(), but compare also the sign.
1757+
1758+
Function useful to compare signed zeros.
1759+
"""
1760+
self.assertEqual(x, y)
1761+
self.assertEqual(math.copysign(1.0, x), math.copysign(1.0, y))
1762+
1763+
@requires_IEEE_754
1764+
def test_nextafter(self):
1765+
# around 2^52 and 2^63
1766+
self.assertEqual(math.nextafter(4503599627370496.0, -INF),
1767+
4503599627370495.5)
1768+
self.assertEqual(math.nextafter(4503599627370496.0, INF),
1769+
4503599627370497.0)
1770+
self.assertEqual(math.nextafter(9223372036854775808.0, 0.0),
1771+
9223372036854774784.0)
1772+
self.assertEqual(math.nextafter(-9223372036854775808.0, 0.0),
1773+
-9223372036854774784.0)
1774+
1775+
# around 1.0
1776+
self.assertEqual(math.nextafter(1.0, -INF),
1777+
float.fromhex('0x1.fffffffffffffp-1'))
1778+
self.assertEqual(math.nextafter(1.0, INF),
1779+
float.fromhex('0x1.0000000000001p+0'))
1780+
1781+
# x == y: y is returned
1782+
self.assertEqual(math.nextafter(2.0, 2.0), 2.0)
1783+
self.assertEqualSign(math.nextafter(-0.0, +0.0), +0.0)
1784+
self.assertEqualSign(math.nextafter(+0.0, -0.0), -0.0)
1785+
1786+
# around 0.0
1787+
smallest_subnormal = sys.float_info.min * sys.float_info.epsilon
1788+
self.assertEqual(math.nextafter(+0.0, INF), smallest_subnormal)
1789+
self.assertEqual(math.nextafter(-0.0, INF), smallest_subnormal)
1790+
self.assertEqual(math.nextafter(+0.0, -INF), -smallest_subnormal)
1791+
self.assertEqual(math.nextafter(-0.0, -INF), -smallest_subnormal)
1792+
self.assertEqualSign(math.nextafter(smallest_subnormal, +0.0), +0.0)
1793+
self.assertEqualSign(math.nextafter(-smallest_subnormal, +0.0), -0.0)
1794+
self.assertEqualSign(math.nextafter(smallest_subnormal, -0.0), +0.0)
1795+
self.assertEqualSign(math.nextafter(-smallest_subnormal, -0.0), -0.0)
1796+
1797+
# around infinity
1798+
largest_normal = sys.float_info.max
1799+
self.assertEqual(math.nextafter(INF, 0.0), largest_normal)
1800+
self.assertEqual(math.nextafter(-INF, 0.0), -largest_normal)
1801+
self.assertEqual(math.nextafter(largest_normal, INF), INF)
1802+
self.assertEqual(math.nextafter(-largest_normal, -INF), -INF)
1803+
1804+
# NaN
1805+
self.assertTrue(math.isnan(math.nextafter(NAN, 1.0)))
1806+
self.assertTrue(math.isnan(math.nextafter(1.0, NAN)))
1807+
self.assertTrue(math.isnan(math.nextafter(NAN, NAN)))
1808+
1809+
@requires_IEEE_754
1810+
def test_ulp(self):
1811+
self.assertEqual(math.ulp(1.0), sys.float_info.epsilon)
1812+
# use int ** int rather than float ** int to not rely on pow() accuracy
1813+
self.assertEqual(math.ulp(2 ** 52), 1.0)
1814+
self.assertEqual(math.ulp(2 ** 53), 2.0)
1815+
self.assertEqual(math.ulp(2 ** 64), 4096.0)
1816+
1817+
# min and max
1818+
self.assertEqual(math.ulp(0.0),
1819+
sys.float_info.min * sys.float_info.epsilon)
1820+
self.assertEqual(math.ulp(FLOAT_MAX),
1821+
FLOAT_MAX - math.nextafter(FLOAT_MAX, -INF))
1822+
1823+
# special cases
1824+
self.assertEqual(math.ulp(INF), INF)
1825+
self.assertTrue(math.isnan(math.ulp(math.nan)))
1826+
1827+
# negative number: ulp(-x) == ulp(x)
1828+
for x in (0.0, 1.0, 2 ** 52, 2 ** 64, INF):
1829+
with self.subTest(x=x):
1830+
self.assertEqual(math.ulp(-x), math.ulp(x))
1831+
17551832

17561833
class IsCloseTests(unittest.TestCase):
17571834
isclose = math.isclose # subclasses should override this
@@ -2009,83 +2086,6 @@ def testComb(self):
20092086
self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int)
20102087
self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int)
20112088

2012-
def assertEqualSign(self, x, y):
2013-
"""Similar to assertEqual(), but compare also the sign.
2014-
2015-
Function useful to compare signed zeros.
2016-
"""
2017-
self.assertEqual(x, y)
2018-
self.assertEqual(math.copysign(1.0, x), math.copysign(1.0, y))
2019-
2020-
@requires_IEEE_754
2021-
def test_nextafter(self):
2022-
# around 2^52 and 2^63
2023-
self.assertEqual(math.nextafter(4503599627370496.0, -INF),
2024-
4503599627370495.5)
2025-
self.assertEqual(math.nextafter(4503599627370496.0, INF),
2026-
4503599627370497.0)
2027-
self.assertEqual(math.nextafter(9223372036854775808.0, 0.0),
2028-
9223372036854774784.0)
2029-
self.assertEqual(math.nextafter(-9223372036854775808.0, 0.0),
2030-
-9223372036854774784.0)
2031-
2032-
# around 1.0
2033-
self.assertEqual(math.nextafter(1.0, -INF),
2034-
float.fromhex('0x1.fffffffffffffp-1'))
2035-
self.assertEqual(math.nextafter(1.0, INF),
2036-
float.fromhex('0x1.0000000000001p+0'))
2037-
2038-
# x == y: y is returned
2039-
self.assertEqual(math.nextafter(2.0, 2.0), 2.0)
2040-
self.assertEqualSign(math.nextafter(-0.0, +0.0), +0.0)
2041-
self.assertEqualSign(math.nextafter(+0.0, -0.0), -0.0)
2042-
2043-
# around 0.0
2044-
smallest_subnormal = sys.float_info.min * sys.float_info.epsilon
2045-
self.assertEqual(math.nextafter(+0.0, INF), smallest_subnormal)
2046-
self.assertEqual(math.nextafter(-0.0, INF), smallest_subnormal)
2047-
self.assertEqual(math.nextafter(+0.0, -INF), -smallest_subnormal)
2048-
self.assertEqual(math.nextafter(-0.0, -INF), -smallest_subnormal)
2049-
self.assertEqualSign(math.nextafter(smallest_subnormal, +0.0), +0.0)
2050-
self.assertEqualSign(math.nextafter(-smallest_subnormal, +0.0), -0.0)
2051-
self.assertEqualSign(math.nextafter(smallest_subnormal, -0.0), +0.0)
2052-
self.assertEqualSign(math.nextafter(-smallest_subnormal, -0.0), -0.0)
2053-
2054-
# around infinity
2055-
largest_normal = sys.float_info.max
2056-
self.assertEqual(math.nextafter(INF, 0.0), largest_normal)
2057-
self.assertEqual(math.nextafter(-INF, 0.0), -largest_normal)
2058-
self.assertEqual(math.nextafter(largest_normal, INF), INF)
2059-
self.assertEqual(math.nextafter(-largest_normal, -INF), -INF)
2060-
2061-
# NaN
2062-
self.assertTrue(math.isnan(math.nextafter(NAN, 1.0)))
2063-
self.assertTrue(math.isnan(math.nextafter(1.0, NAN)))
2064-
self.assertTrue(math.isnan(math.nextafter(NAN, NAN)))
2065-
2066-
@requires_IEEE_754
2067-
def test_ulp(self):
2068-
self.assertEqual(math.ulp(1.0), sys.float_info.epsilon)
2069-
# use int ** int rather than float ** int to not rely on pow() accuracy
2070-
self.assertEqual(math.ulp(2 ** 52), 1.0)
2071-
self.assertEqual(math.ulp(2 ** 53), 2.0)
2072-
self.assertEqual(math.ulp(2 ** 64), 4096.0)
2073-
2074-
# min and max
2075-
self.assertEqual(math.ulp(0.0),
2076-
sys.float_info.min * sys.float_info.epsilon)
2077-
self.assertEqual(math.ulp(FLOAT_MAX),
2078-
FLOAT_MAX - math.nextafter(FLOAT_MAX, -INF))
2079-
2080-
# special cases
2081-
self.assertEqual(math.ulp(INF), INF)
2082-
self.assertTrue(math.isnan(math.ulp(math.nan)))
2083-
2084-
# negative number: ulp(-x) == ulp(x)
2085-
for x in (0.0, 1.0, 2 ** 52, 2 ** 64, INF):
2086-
with self.subTest(x=x):
2087-
self.assertEqual(math.ulp(-x), math.ulp(x))
2088-
20892089

20902090
def test_main():
20912091
from doctest import DocFileSuite
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix ``math.nextafter(-0.0, +0.0)`` on AIX 7.1.

Modules/mathmodule.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,8 +3287,14 @@ static PyObject *
32873287
math_nextafter_impl(PyObject *module, double x, double y)
32883288
/*[clinic end generated code: output=750c8266c1c540ce input=02b2d50cd1d9f9b6]*/
32893289
{
3290-
double f = nextafter(x, y);
3291-
return PyFloat_FromDouble(f);
3290+
#if defined(_AIX)
3291+
if (x == y) {
3292+
/* On AIX 7.1, libm nextafter(-0.0, +0.0) returns -0.0.
3293+
Bug fixed in bos.adt.libm 7.2.2.0 by APAR IV95512. */
3294+
return PyFloat_FromDouble(y);
3295+
}
3296+
#endif
3297+
return PyFloat_FromDouble(nextafter(x, y));
32923298
}
32933299

32943300

0 commit comments

Comments
 (0)