How would you work out 313? The obvious way is to start with 3 and multiply by 3 twelve more times. But there is a shortcut. 313 is 3 × 312, and 312 is the square of 36, and 36 is the square of 33. Each step halves the exponent. Watch how few multiplications that leaves.
Raising to a power in few steps
3¹³ by halving the exponent
#include <stdio.h> static int mults = 0; long long power(long long x, int n){ if (n == 0) return 1; long long half = power(x, n / 2); long long result = half * half; mults++; if (n % 2 == 1) { result = result * x; mults++; } return result;} long long power_loop(long long x, int n){ long long result = x; for (int i = 1; i < n; i++) { result = result * x; mults++; } return result;} int main(void){ long long a = power(3, 13); printf("power: %lld in %d multiplications\n", a, mults); mults = 0; long long b = power_loop(3, 13); printf("loop: %lld in %d multiplications\n", b, mults); return 0;}main calls power(3, 13).
- multiplications by power
- 0
- by the loop
- 0
Output
Describe this picture
The 37 lines of power.c with the line about to run marked, beside a picture in two parts. At the top, under the label “Call stack”, is one card per call that has not returned yet: main’s with its a and b, then cards named power(3, 13), power(3, 6) and so on, each with two boxes, half and result, a ”?” until written. The running call’s card is edged in the accent colour; a returning card shows the value it hands back in a badge, and that value flies into the half box of the card above. Below the stack is a row of four bit cells, labelled under the row “13 in binary: each call’s n % 2”. Each cell holds 1 or 0, and the label over it names the call it belongs to: n=1, n=3, n=6 and n=13, from left to right, which reads 1 1 0 1. Cells of calls that have not tested their n yet are greyed; a cell whose call is testing its n is outlined. The clip plays the program once, about 23 seconds, and rests on the end. First, five cards pile up as 13 halves to 6, 3, 1 and 0. power(3, 0) returns 1. Then, on the way back, each card squares its half and, when its n is odd, multiplies by 3 once more, and its bit lights in the row from the left: power(3, 1) returns 3, power(3, 3) returns 27, power(3, 6) returns 729 and power(3, 13) returns 1594323. Then power_loop(3, 13) runs quickly in one card, its result multiplied by 3 twelve times while i counts from 1 to 12. Under the picture are one sentence on the current step, two readouts, “multiplications by power” (it ends at 7) and “by the loop” (it ends at 12), and the output: power: 1594323 in 7 multiplications and loop: 1594323 in 12 multiplications. The transport plays and pauses, steps back or forward, and scrubs; a paused step is kept in the page address as fast-power.step.
Halving the exponent
Here is the rule the program uses. When n is even, xn is xn/2 times itself. When n is odd, take one x out first:
The brackets ⌊ ⌋ mean “rounded down”, which is what n / 2 does in C when n is an int: 13 / 2 is 6. So it works for every n, not only powers of 2. In C:
long long power(long long x, int n)
{
if (n == 0)
return 1;
long long half = power(x, n / 2);
long long result = half * half;
mults++;
if (n % 2 == 1) {
result = result * x;
mults++;
}
return result;
}
In the clip, 13 halves to 6, then 3, then 1, then 0, and the base case returns 1. Then the cards return, the deepest first:
| Call | half | squared | n odd? | returns | multiplications so far |
|---|---|---|---|---|---|
| power(3, 1) | 1 | 1 × 1 = 1 | yes: × 3 | 3 | 2 |
| power(3, 3) | 3 | 3 × 3 = 9 | yes: × 3 | 27 | 4 |
| power(3, 6) | 27 | 27 × 27 = 729 | no | 729 | 5 |
| power(3, 13) | 729 | 729 × 729 = 531,441 | yes: × 3 | 1,594,323 | 7 |
Seven multiplications, against the loop’s twelve.
Key idea
To raise x to the power n, raise it to the power n/2 (rounded down) and square the answer; if n is odd, multiply by x once more. The exponent halves at every call.
The code and its cost
The bits of n
Look at the row of bits in the clip. Each call’s n is the one above it halved, so each call’s n % 2, odd or even, is one bit of 13 written in binary. Read from the deepest call to the first, the bits are 1, 1, 0, 1, and 1101 in binary is 8 + 4 + 0 + 1 = 13.
That gives the count. Every call with n above 0 makes one squaring, and there is one call for each bit of n. Every 1 bit adds one multiplication by x. So:
For 13, that is 4 + 3 = 7. The number of bits of n is ⌊log₂ n⌋ + 1, so the count is at most about 2 log₂ n. The loop always needs n − 1. In the notation of Time and space complexity (3.3), the halving version takes O(log n) time and the loop O(n). The stack holds one frame per bit, O(log n) as well.
The work here is the multiplications: everything else a call does is a test, a halving and a return. So fewer multiplications really is less work.
The loop that reads the bits
The same idea works without recursion. Go through the bits of n from the right. Keep x squared as you go, so at each bit x holds 3, 9, 81, 6561: the powers 31, 32, 34, 38. Whenever the bit is 1, multiply the result by the current x:
long long power_bits(long long x, int n)
{
long long result = 1;
while (n > 0) {
if (n % 2 == 1)
result = result * x;
x = x * x;
n = n / 2;
}
return result;
}
This uses one frame. It reads the same bits as the recursion, in the opposite order.
The plain loop
power_loop in the program is the obvious method: start with x and multiply by x, n − 1 times. It only works for n of 1 or more; for n = 0 it would return x instead of 1.
Running it yourself
gcc -std=c11 -Wall -Wextra -pedantic power.c -o power
./power
It prints power: 1594323 in 7 multiplications, then loop: 1594323 in 12 multiplications.
Worked example
The bit loop for 313, by hand. Each row is the state at the top of the while loop:
| n | its last bit | result | x |
|---|---|---|---|
| 13 | 1 | 1 | 3 |
| 6 | 0 | 3 | 9 |
| 3 | 1 | 3 | 81 |
| 1 | 1 | 243 | 6,561 |
| 0 | (stop) | 1,594,323 | 43,046,721 |
At n = 13 the bit is 1, so result becomes 1 × 3 = 3. At n = 6 it is 0, and only x changes. At n = 3, result becomes 3 × 81 = 243. At n = 1, result becomes 243 × 6,561 = 1,594,323.
A million. In binary, 1,000,000 is 11110100001001000000: 20 bits, 7 of them 1. So power makes 20 + 7 = 27 multiplications, where the loop would make 999,999. A program that counts them, power-mod.c, agrees: 27.
Overflow. 31,000,000 has far too many digits for any C integer. The largest long long here is 9,223,372,036,854,775,807. 339 = 4,052,555,153,018,976,267 fits; 340 = 12,157,665,459,056,928,801 does not, and multiplying past it is undefined in C.
Remainders. To get past that, many programs keep only the remainder after dividing by some number m, at every step. The remainder of a product depends only on the remainders of the factors, so the answer comes out right. With m = 7, power-mod.c gets 313 mod 7 = 3. Check: 1,594,323 = 7 × 227,760 + 3. It also gets 31,000,000 mod 1,000,000,007 = 64,935,414, in those 27 multiplications.
Where it’s used
Public-key cryptography. Encryption methods such as RSA raise a number to a power with hundreds of digits, keeping remainders at every step. The loop would never finish. Halving needs a few thousand multiplications at most.
Powers of a matrix. The same rule squares matrices instead of numbers. In linear algebra, Diagonalisation gives another way to raise a matrix to a power. A 2 × 2 matrix raised to the power n by halving gives fib(n) in O(log n) multiplications, against the exponential calls of Tree recursion (4.3).
Maths libraries. Functions that raise a number to a whole-number power use this method, because it needs so few multiplications.
Reference card
| Idea | In this lesson |
|---|---|
| halving rule | xn = (xn/2)2 for even n; x · (x⌊n/2⌋)2 for odd n; x0 = 1 |
| calls | one per bit of n, plus the base case: 13, 6, 3, 1, 0 |
| multiplications | bits of n + 1 bits of n; 313: 4 + 3 = 7 |
| cost | O(log n) time and stack; the loop O(n) time |
| the bits | each call’s n % 2 is one bit of n: 13 = 1101 |
| loop form | if n is odd multiply result by x; square x; halve n |
| limits | a long long holds 339 but not 340 |
| remainders | keep the remainder at each step: 313 mod 7 = 3 |
Platform: C11, gcc on x86-64 Linux: int 4 bytes, long long 8. The cards in the picture show names and values only.