Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Exact integer exponentiation (like ``i**2`` or ``pow(i, 2)``) with a small exponent is much faster, due to reducing overhead in such cases.
41 changes: 36 additions & 5 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -4239,17 +4239,48 @@ long_pow(PyObject *v, PyObject *w, PyObject *x)
REDUCE(result); \
} while(0)

if (Py_SIZE(b) <= FIVEARY_CUTOFF) {
i = Py_SIZE(b);
digit bi = i ? b->ob_digit[i-1] : 0;
digit bit;
if (i <= 1 && bi <= 3) {
/* exponent <= 3 - just do straight multiplies. Note that the multiply
* 1 * a -> z serves a purpose when bi is 1: if `a` is of an int
* subclass, it ensures the result is an int. For example, that
* pow(False, 1) returns 0 instead of False.
*/
while (bi-- > 0) {
MULT(z, a, z);
}
}
else if (i <= FIVEARY_CUTOFF) {
/* Left-to-right binary exponentiation (HAC Algorithm 14.79) */
/* http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf */
for (i = Py_SIZE(b) - 1; i >= 0; --i) {
digit bi = b->ob_digit[i];

for (j = (digit)1 << (PyLong_SHIFT-1); j != 0; j >>= 1) {
/* Find the first significant exponent bit. Search right to left
* because we're primarily trying to cut overhead for small powers.
*/
assert(bi); /* else there is no significant bit */
for (bit = 2; ; bit <<= 1) {
if (bit > bi) { /* found the first bit */
assert((bi & bit) == 0);
bit >>= 1;
MULT(z, a, z);
break;
}
}
assert(bi & bit);
for (--i, bit >>= 1;;) {
for (; bit != 0; bit >>= 1) {
MULT(z, z, z);
if (bi & j)
if (bi & bit) {
MULT(z, a, z);
}
}
if (--i < 0) {
break;
}
bi = b->ob_digit[i];
bit = (digit)1 << (PyLong_SHIFT-1);
}
}
else {
Expand Down