bpo-39288: Add math.nextafter(x, y) (GH-17937)
Return the next floating-point value after x towards y.
This commit is contained in:
parent
1b335ae281
commit
100fafcf20
|
@ -213,6 +213,14 @@ Number-theoretic and representation functions
|
|||
of *x* and are floats.
|
||||
|
||||
|
||||
.. function:: nextafter(x, y)
|
||||
|
||||
Return the next floating-point value after *x* towards *y*.
|
||||
|
||||
If *x* is equal to *y*, return *y*.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
.. function:: perm(n, k=None)
|
||||
|
||||
Return the number of ways to choose *k* items from *n* items
|
||||
|
|
|
@ -177,6 +177,13 @@ with this change. The overridden methods of :class:`~imaplib.IMAP4_SSL` and
|
|||
:class:`~imaplib.IMAP4_stream` were applied to this change.
|
||||
(Contributed by Dong-hee Na in :issue:`38615`.)
|
||||
|
||||
math
|
||||
----
|
||||
|
||||
Add :func:`math.nextafter`: return the next floating-point value after *x*
|
||||
towards *y*.
|
||||
(Contributed by Victor Stinner in :issue:`39288`.)
|
||||
|
||||
nntplib
|
||||
-------
|
||||
|
||||
|
|
|
@ -2033,6 +2033,60 @@ class IsCloseTests(unittest.TestCase):
|
|||
self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int)
|
||||
self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int)
|
||||
|
||||
def assertEqualSign(self, x, y):
|
||||
"""Similar to assertEqual(), but compare also the sign.
|
||||
|
||||
Function useful to check to signed zero.
|
||||
"""
|
||||
self.assertEqual(x, y)
|
||||
self.assertEqual(math.copysign(1.0, x), math.copysign(1.0, y))
|
||||
|
||||
@requires_IEEE_754
|
||||
def test_nextafter(self):
|
||||
# around 2^52 and 2^63
|
||||
self.assertEqual(math.nextafter(4503599627370496.0, -INF),
|
||||
4503599627370495.5)
|
||||
self.assertEqual(math.nextafter(4503599627370496.0, INF),
|
||||
4503599627370497.0)
|
||||
self.assertEqual(math.nextafter(9223372036854775808.0, 0.0),
|
||||
9223372036854774784.0)
|
||||
self.assertEqual(math.nextafter(-9223372036854775808.0, 0.0),
|
||||
-9223372036854774784.0)
|
||||
|
||||
# around 1.0
|
||||
self.assertEqual(math.nextafter(1.0, -INF),
|
||||
float.fromhex('0x1.fffffffffffffp-1'))
|
||||
self.assertEqual(math.nextafter(1.0, INF),
|
||||
float.fromhex('0x1.0000000000001p+0'))
|
||||
|
||||
# x == y: y is returned
|
||||
self.assertEqual(math.nextafter(2.0, 2.0), 2.0)
|
||||
self.assertEqualSign(math.nextafter(-0.0, +0.0), +0.0)
|
||||
self.assertEqualSign(math.nextafter(+0.0, -0.0), -0.0)
|
||||
|
||||
# around 0.0
|
||||
smallest_subnormal = sys.float_info.min * sys.float_info.epsilon
|
||||
self.assertEqual(math.nextafter(+0.0, INF), smallest_subnormal)
|
||||
self.assertEqual(math.nextafter(-0.0, INF), smallest_subnormal)
|
||||
self.assertEqual(math.nextafter(+0.0, -INF), -smallest_subnormal)
|
||||
self.assertEqual(math.nextafter(-0.0, -INF), -smallest_subnormal)
|
||||
self.assertEqualSign(math.nextafter(smallest_subnormal, +0.0), +0.0)
|
||||
self.assertEqualSign(math.nextafter(-smallest_subnormal, +0.0), -0.0)
|
||||
self.assertEqualSign(math.nextafter(smallest_subnormal, -0.0), +0.0)
|
||||
self.assertEqualSign(math.nextafter(-smallest_subnormal, -0.0), -0.0)
|
||||
|
||||
# around infinity
|
||||
largest_normal = sys.float_info.max
|
||||
self.assertEqual(math.nextafter(INF, 0.0), largest_normal)
|
||||
self.assertEqual(math.nextafter(-INF, 0.0), -largest_normal)
|
||||
self.assertEqual(math.nextafter(largest_normal, INF), INF)
|
||||
self.assertEqual(math.nextafter(-largest_normal, -INF), -INF)
|
||||
|
||||
# NaN
|
||||
self.assertTrue(math.isnan(math.nextafter(NAN, 1.0)))
|
||||
self.assertTrue(math.isnan(math.nextafter(1.0, NAN)))
|
||||
self.assertTrue(math.isnan(math.nextafter(NAN, NAN)))
|
||||
|
||||
|
||||
def test_main():
|
||||
from doctest import DocFileSuite
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Add :func:`math.nextafter`: return the next floating-point value after *x*
|
||||
towards *y*.
|
|
@ -808,4 +808,52 @@ math_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
|||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=9a2b3dc91eb9aadd input=a9049054013a1b77]*/
|
||||
|
||||
PyDoc_STRVAR(math_nextafter__doc__,
|
||||
"nextafter($module, x, y, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return the next floating-point value after x towards y.");
|
||||
|
||||
#define MATH_NEXTAFTER_METHODDEF \
|
||||
{"nextafter", (PyCFunction)(void(*)(void))math_nextafter, METH_FASTCALL, math_nextafter__doc__},
|
||||
|
||||
static PyObject *
|
||||
math_nextafter_impl(PyObject *module, double x, double y);
|
||||
|
||||
static PyObject *
|
||||
math_nextafter(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
double x;
|
||||
double y;
|
||||
|
||||
if (!_PyArg_CheckPositional("nextafter", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
if (PyFloat_CheckExact(args[0])) {
|
||||
x = PyFloat_AS_DOUBLE(args[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = PyFloat_AsDouble(args[0]);
|
||||
if (x == -1.0 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
if (PyFloat_CheckExact(args[1])) {
|
||||
y = PyFloat_AS_DOUBLE(args[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
y = PyFloat_AsDouble(args[1]);
|
||||
if (y == -1.0 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
return_value = math_nextafter_impl(module, x, y);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=e4ed1a800e4b2eae input=a9049054013a1b77]*/
|
||||
|
|
|
@ -3295,6 +3295,25 @@ error:
|
|||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
math.nextafter
|
||||
|
||||
x: double
|
||||
y: double
|
||||
/
|
||||
|
||||
Return the next floating-point value after x towards y.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
math_nextafter_impl(PyObject *module, double x, double y)
|
||||
/*[clinic end generated code: output=750c8266c1c540ce input=02b2d50cd1d9f9b6]*/
|
||||
{
|
||||
double f = nextafter(x, y);
|
||||
return PyFloat_FromDouble(f);
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef math_methods[] = {
|
||||
{"acos", math_acos, METH_O, math_acos_doc},
|
||||
{"acosh", math_acosh, METH_O, math_acosh_doc},
|
||||
|
@ -3346,6 +3365,7 @@ static PyMethodDef math_methods[] = {
|
|||
MATH_PROD_METHODDEF
|
||||
MATH_PERM_METHODDEF
|
||||
MATH_COMB_METHODDEF
|
||||
MATH_NEXTAFTER_METHODDEF
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue