From f84d42146a8270b096a1b3c360c355347bffc2fa Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 16 Jun 2025 11:46:37 +0300 Subject: [PATCH 1/2] gh-102221: Optimize math.lcm() for multiple arguments --- Modules/mathmodule.c | 64 +++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 7c2a421dd6a450..b99460d6a83077 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -788,6 +788,39 @@ long_lcm(PyObject *a, PyObject *b) return ab; } +static PyObject * +long_array_lcm(PyObject * const *args, Py_ssize_t args_length) +{ + if (args_length == 1) { + return PyNumber_Index(args[0]); + } + + PyObject *left, *right; + if (args_length == 2) { + left = PyNumber_Index(args[0]); + if (left == NULL) { + return NULL; + } + right = PyNumber_Index(args[1]); + } + else { + Py_ssize_t half = args_length / 2; + left = long_array_lcm(args, half); + if (left == NULL) { + return NULL; + } + right = long_array_lcm(args + half, args_length - half); + } + if (right == NULL) { + Py_DECREF(left); + return NULL; + } + PyObject *res = long_lcm(left, right); + Py_DECREF(left); + Py_DECREF(right); + return res; +} + /*[clinic input] math.lcm @@ -802,41 +835,18 @@ math_lcm_impl(PyObject *module, PyObject * const *args, Py_ssize_t args_length) /*[clinic end generated code: output=c8a59a5c2e55c816 input=3e4f4b7cdf948a98]*/ { - PyObject *res, *x; - Py_ssize_t i; - if (args_length == 0) { return PyLong_FromLong(1); } - res = PyNumber_Index(args[0]); - if (res == NULL) { - return NULL; - } if (args_length == 1) { - Py_SETREF(res, PyNumber_Absolute(res)); - return res; - } - - PyObject *zero = _PyLong_GetZero(); // borrowed ref - for (i = 1; i < args_length; i++) { - x = PyNumber_Index(args[i]); - if (x == NULL) { - Py_DECREF(res); - return NULL; - } - if (res == zero) { - /* Fast path: just check arguments. - It is okay to use identity comparison here. */ - Py_DECREF(x); - continue; - } - Py_SETREF(res, long_lcm(res, x)); - Py_DECREF(x); + PyObject *res = PyNumber_Index(args[0]); if (res == NULL) { return NULL; } + Py_SETREF(res, PyNumber_Absolute(res)); + return res; } - return res; + return long_array_lcm(args, args_length); } From 1cf0a9b49e14329c961e8915291fdc0d0eedba37 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 26 Apr 2026 11:52:52 +0300 Subject: [PATCH 2/2] Add a NEWS entry. --- .../next/Library/2026-04-26-11-47-17.gh-issue-102221.m0wyOh.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2026-04-26-11-47-17.gh-issue-102221.m0wyOh.rst diff --git a/Misc/NEWS.d/next/Library/2026-04-26-11-47-17.gh-issue-102221.m0wyOh.rst b/Misc/NEWS.d/next/Library/2026-04-26-11-47-17.gh-issue-102221.m0wyOh.rst new file mode 100644 index 00000000000000..241f3f76698dca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-26-11-47-17.gh-issue-102221.m0wyOh.rst @@ -0,0 +1 @@ +Optimize :func:`math.integer.lcm` for multiple arguments.