Skip to content

Commit 100fafc

Browse files
authored
bpo-39288: Add math.nextafter(x, y) (GH-17937)
Return the next floating-point value after x towards y.
1 parent 1b335ae commit 100fafc

File tree

6 files changed

+140
-1
lines changed

6 files changed

+140
-1
lines changed

Doc/library/math.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,14 @@ Number-theoretic and representation functions
213213
of *x* and are floats.
214214

215215

216+
.. function:: nextafter(x, y)
217+
218+
Return the next floating-point value after *x* towards *y*.
219+
220+
If *x* is equal to *y*, return *y*.
221+
222+
.. versionadded:: 3.9
223+
216224
.. function:: perm(n, k=None)
217225

218226
Return the number of ways to choose *k* items from *n* items

Doc/whatsnew/3.9.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,13 @@ with this change. The overridden methods of :class:`~imaplib.IMAP4_SSL` and
177177
:class:`~imaplib.IMAP4_stream` were applied to this change.
178178
(Contributed by Dong-hee Na in :issue:`38615`.)
179179

180+
math
181+
----
182+
183+
Add :func:`math.nextafter`: return the next floating-point value after *x*
184+
towards *y*.
185+
(Contributed by Victor Stinner in :issue:`39288`.)
186+
180187
nntplib
181188
-------
182189

Lib/test/test_math.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,60 @@ def testComb(self):
20332033
self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int)
20342034
self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int)
20352035

2036+
def assertEqualSign(self, x, y):
2037+
"""Similar to assertEqual(), but compare also the sign.
2038+
2039+
Function useful to check to signed zero.
2040+
"""
2041+
self.assertEqual(x, y)
2042+
self.assertEqual(math.copysign(1.0, x), math.copysign(1.0, y))
2043+
2044+
@requires_IEEE_754
2045+
def test_nextafter(self):
2046+
# around 2^52 and 2^63
2047+
self.assertEqual(math.nextafter(4503599627370496.0, -INF),
2048+
4503599627370495.5)
2049+
self.assertEqual(math.nextafter(4503599627370496.0, INF),
2050+
4503599627370497.0)
2051+
self.assertEqual(math.nextafter(9223372036854775808.0, 0.0),
2052+
9223372036854774784.0)
2053+
self.assertEqual(math.nextafter(-9223372036854775808.0, 0.0),
2054+
-9223372036854774784.0)
2055+
2056+
# around 1.0
2057+
self.assertEqual(math.nextafter(1.0, -INF),
2058+
float.fromhex('0x1.fffffffffffffp-1'))
2059+
self.assertEqual(math.nextafter(1.0, INF),
2060+
float.fromhex('0x1.0000000000001p+0'))
2061+
2062+
# x == y: y is returned
2063+
self.assertEqual(math.nextafter(2.0, 2.0), 2.0)
2064+
self.assertEqualSign(math.nextafter(-0.0, +0.0), +0.0)
2065+
self.assertEqualSign(math.nextafter(+0.0, -0.0), -0.0)
2066+
2067+
# around 0.0
2068+
smallest_subnormal = sys.float_info.min * sys.float_info.epsilon
2069+
self.assertEqual(math.nextafter(+0.0, INF), smallest_subnormal)
2070+
self.assertEqual(math.nextafter(-0.0, INF), smallest_subnormal)
2071+
self.assertEqual(math.nextafter(+0.0, -INF), -smallest_subnormal)
2072+
self.assertEqual(math.nextafter(-0.0, -INF), -smallest_subnormal)
2073+
self.assertEqualSign(math.nextafter(smallest_subnormal, +0.0), +0.0)
2074+
self.assertEqualSign(math.nextafter(-smallest_subnormal, +0.0), -0.0)
2075+
self.assertEqualSign(math.nextafter(smallest_subnormal, -0.0), +0.0)
2076+
self.assertEqualSign(math.nextafter(-smallest_subnormal, -0.0), -0.0)
2077+
2078+
# around infinity
2079+
largest_normal = sys.float_info.max
2080+
self.assertEqual(math.nextafter(INF, 0.0), largest_normal)
2081+
self.assertEqual(math.nextafter(-INF, 0.0), -largest_normal)
2082+
self.assertEqual(math.nextafter(largest_normal, INF), INF)
2083+
self.assertEqual(math.nextafter(-largest_normal, -INF), -INF)
2084+
2085+
# NaN
2086+
self.assertTrue(math.isnan(math.nextafter(NAN, 1.0)))
2087+
self.assertTrue(math.isnan(math.nextafter(1.0, NAN)))
2088+
self.assertTrue(math.isnan(math.nextafter(NAN, NAN)))
2089+
20362090

20372091
def test_main():
20382092
from doctest import DocFileSuite
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add :func:`math.nextafter`: return the next floating-point value after *x*
2+
towards *y*.

Modules/clinic/mathmodule.c.h

Lines changed: 49 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/mathmodule.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3295,6 +3295,25 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k)
32953295
}
32963296

32973297

3298+
/*[clinic input]
3299+
math.nextafter
3300+
3301+
x: double
3302+
y: double
3303+
/
3304+
3305+
Return the next floating-point value after x towards y.
3306+
[clinic start generated code]*/
3307+
3308+
static PyObject *
3309+
math_nextafter_impl(PyObject *module, double x, double y)
3310+
/*[clinic end generated code: output=750c8266c1c540ce input=02b2d50cd1d9f9b6]*/
3311+
{
3312+
double f = nextafter(x, y);
3313+
return PyFloat_FromDouble(f);
3314+
}
3315+
3316+
32983317
static PyMethodDef math_methods[] = {
32993318
{"acos", math_acos, METH_O, math_acos_doc},
33003319
{"acosh", math_acosh, METH_O, math_acosh_doc},
@@ -3346,6 +3365,7 @@ static PyMethodDef math_methods[] = {
33463365
MATH_PROD_METHODDEF
33473366
MATH_PERM_METHODDEF
33483367
MATH_COMB_METHODDEF
3368+
MATH_NEXTAFTER_METHODDEF
33493369
{NULL, NULL} /* sentinel */
33503370
};
33513371

0 commit comments

Comments
 (0)