Skip to content

Commit 9d8dd8f

Browse files
authored
bpo-44376 - reduce pow() overhead for small exponents (GH-26662)
Greatly reduce pow() overhead for small exponents.
1 parent be8b631 commit 9d8dd8f

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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.

Objects/longobject.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4239,17 +4239,57 @@ long_pow(PyObject *v, PyObject *w, PyObject *x)
42394239
REDUCE(result); \
42404240
} while(0)
42414241

4242-
if (Py_SIZE(b) <= FIVEARY_CUTOFF) {
4242+
i = Py_SIZE(b);
4243+
digit bi = i ? b->ob_digit[i-1] : 0;
4244+
digit bit;
4245+
if (i <= 1 && bi <= 3) {
4246+
/* aim for minimal overhead */
4247+
if (bi >= 2) {
4248+
MULT(a, a, z);
4249+
if (bi == 3) {
4250+
MULT(z, a, z);
4251+
}
4252+
}
4253+
else if (bi == 1) {
4254+
/* Multiplying by 1 serves two purposes: if `a` is of an int
4255+
* subclass, makes the result an int (e.g., pow(False, 1) returns
4256+
* 0 instead of False), and potentially reduces `a` by the modulus.
4257+
*/
4258+
MULT(a, z, z);
4259+
}
4260+
/* else bi is 0, and z==1 is correct */
4261+
}
4262+
else if (i <= FIVEARY_CUTOFF) {
42434263
/* Left-to-right binary exponentiation (HAC Algorithm 14.79) */
42444264
/* http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf */
4245-
for (i = Py_SIZE(b) - 1; i >= 0; --i) {
4246-
digit bi = b->ob_digit[i];
42474265

4248-
for (j = (digit)1 << (PyLong_SHIFT-1); j != 0; j >>= 1) {
4266+
/* Find the first significant exponent bit. Search right to left
4267+
* because we're primarily trying to cut overhead for small powers.
4268+
*/
4269+
assert(bi); /* else there is no significant bit */
4270+
Py_INCREF(a);
4271+
Py_DECREF(z);
4272+
z = a;
4273+
for (bit = 2; ; bit <<= 1) {
4274+
if (bit > bi) { /* found the first bit */
4275+
assert((bi & bit) == 0);
4276+
bit >>= 1;
4277+
assert(bi & bit);
4278+
break;
4279+
}
4280+
}
4281+
for (--i, bit >>= 1;;) {
4282+
for (; bit != 0; bit >>= 1) {
42494283
MULT(z, z, z);
4250-
if (bi & j)
4284+
if (bi & bit) {
42514285
MULT(z, a, z);
4286+
}
4287+
}
4288+
if (--i < 0) {
4289+
break;
42524290
}
4291+
bi = b->ob_digit[i];
4292+
bit = (digit)1 << (PyLong_SHIFT-1);
42534293
}
42544294
}
42554295
else {

0 commit comments

Comments
 (0)