diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-18-10-39-56.gh-issue-157742.JFOuHy.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-18-10-39-56.gh-issue-157742.JFOuHy.rst new file mode 100644 index 00000000000000..02e911a8893cf0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-18-10-39-56.gh-issue-157742.JFOuHy.rst @@ -0,0 +1 @@ +Improve performance of multiplication of :class:`int`. diff --git a/Objects/longobject.c b/Objects/longobject.c index f5526213944011..a5dc6763d4b249 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3939,8 +3939,8 @@ x_mul(PyLongObject *a, PyLongObject *b) if (z == NULL) return NULL; - memset(z->long_value.ob_digit, 0, _PyLong_DigitCount(z) * sizeof(digit)); if (a == b) { + memset(z->long_value.ob_digit, 0, _PyLong_DigitCount(z) * sizeof(digit)); /* Efficient squaring per HAC, Algorithm 14.16: * https://cacr.uwaterloo.ca/hac/about/chap14.pdf * Gives slightly less than a 2x speedup when a == b, @@ -4011,15 +4011,17 @@ x_mul(PyLongObject *a, PyLongObject *b) return NULL; }); + /* Row 0 has nothing to add to yet (z is not zeroed); every + later row only reads digits that the previous row wrote. + Compilers split the i == 0 row off into its own loop. */ while (pb < pbend) { - carry += *pz + *pb++ * f; + carry += (i ? *pz : 0) + *pb++ * f; *pz++ = (digit)(carry & PyLong_MASK); carry >>= PyLong_SHIFT; assert(carry <= PyLong_MASK); } - if (carry) - *pz += (digit)(carry & PyLong_MASK); assert((carry >> PyLong_SHIFT) == 0); + *pz = (digit)carry; } } return long_normalize(z);