From 5a2bac7fe0e7a2b67fd57c7a9176a50feed0d7a0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 20 Jul 2020 15:57:37 +0300 Subject: [PATCH] bpo-41342: Convert int.__round__ to Argument Clinic (GH-21549) --- .../2020-07-19-15-40-52.bpo-41342.RRk_m_.rst | 1 + Objects/clinic/longobject.c.h | 36 ++++++++++++++++++- Objects/longobject.c | 22 ++++++++---- 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-07-19-15-40-52.bpo-41342.RRk_m_.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-07-19-15-40-52.bpo-41342.RRk_m_.rst b/Misc/NEWS.d/next/Core and Builtins/2020-07-19-15-40-52.bpo-41342.RRk_m_.rst new file mode 100644 index 00000000000..38851a7f7fc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-07-19-15-40-52.bpo-41342.RRk_m_.rst @@ -0,0 +1 @@ +:func:`round` with integer argument is now faster (9--60%). diff --git a/Objects/clinic/longobject.c.h b/Objects/clinic/longobject.c.h index cf388c50f5a..4bd47b116f8 100644 --- a/Objects/clinic/longobject.c.h +++ b/Objects/clinic/longobject.c.h @@ -87,6 +87,40 @@ exit: return return_value; } +PyDoc_STRVAR(int___round____doc__, +"__round__($self, ndigits=, /)\n" +"--\n" +"\n" +"Rounding an Integral returns itself.\n" +"\n" +"Rounding with an ndigits argument also returns an integer."); + +#define INT___ROUND___METHODDEF \ + {"__round__", (PyCFunction)(void(*)(void))int___round__, METH_FASTCALL, int___round____doc__}, + +static PyObject * +int___round___impl(PyObject *self, PyObject *o_ndigits); + +static PyObject * +int___round__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *o_ndigits = NULL; + + if (!_PyArg_CheckPositional("__round__", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + o_ndigits = args[0]; +skip_optional: + return_value = int___round___impl(self, o_ndigits); + +exit: + return return_value; +} + PyDoc_STRVAR(int___sizeof____doc__, "__sizeof__($self, /)\n" "--\n" @@ -333,4 +367,4 @@ skip_optional_kwonly: exit: return return_value; } -/*[clinic end generated code: output=4257cfdb155efd00 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ea18e51af5b53591 input=a9049054013a1b77]*/ diff --git a/Objects/longobject.c b/Objects/longobject.c index 571f53a3c00..92514d4154e 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5155,10 +5155,22 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) return NULL; } +/*[clinic input] +int.__round__ + + ndigits as o_ndigits: object = NULL + / + +Rounding an Integral returns itself. + +Rounding with an ndigits argument also returns an integer. +[clinic start generated code]*/ + static PyObject * -long_round(PyObject *self, PyObject *args) +int___round___impl(PyObject *self, PyObject *o_ndigits) +/*[clinic end generated code: output=954fda6b18875998 input=1614cf23ec9e18c3]*/ { - PyObject *o_ndigits=NULL, *temp, *result, *ndigits; + PyObject *temp, *result, *ndigits; /* To round an integer m to the nearest 10**n (n positive), we make use of * the divmod_near operation, defined by: @@ -5174,8 +5186,6 @@ long_round(PyObject *self, PyObject *args) * * m - divmod_near(m, 10**n)[1]. */ - if (!PyArg_ParseTuple(args, "|O", &o_ndigits)) - return NULL; if (o_ndigits == NULL) return long_long(self); @@ -5536,9 +5546,7 @@ static PyMethodDef long_methods[] = { "Flooring an Integral returns itself."}, {"__ceil__", long_long_meth, METH_NOARGS, "Ceiling of an Integral returns itself."}, - {"__round__", (PyCFunction)long_round, METH_VARARGS, - "Rounding an Integral returns itself.\n" - "Rounding with an ndigits argument also returns an integer."}, + INT___ROUND___METHODDEF INT___GETNEWARGS___METHODDEF INT___FORMAT___METHODDEF INT___SIZEOF___METHODDEF