Pow(x, n)
A medium problem from Math & Geometry. Try it first, open a hint when you are stuck, and read the solution when you are done.
- Medium
- Math & Geometry
The problem
Return x raised to the power n without using your language's built-in power operator or function. x can be negative or have a decimal part. n is a whole number from -2,147,483,648 to 2,147,483,647. A negative power is 1 divided by the matching positive power, so 2 to the power -2 is 0.25, and x is never 0 when n is negative. Anything to the power 0 is 1, including 0. The tests accept an answer within 0.000000001 of the expected value, or within 0.000000001 times that value when it is larger than 1, ignoring signs.
What to write
function solve(x: number, n: number): numberExample 1
Input x = 2 n = 10 Output 1024
2 to the power 10 means ten 2s multiplied together: 2 × 2 × 2 × 2 × 2 × 2 × 2 × 2 × 2 × 2 = 1024.
Example 2
Input x = 2.1 n = 3 Output 9.261
2.1 to the power 3 is 2.1 × 2.1 × 2.1 = 9.261. A computer's decimal arithmetic is slightly inexact, so your program may produce 9.261000000000001 instead. The tests accept that, because it is well within 0.000000001 times 9.261 of the expected value.
Constraints
Test results are finite.
Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1: Use the constraints
ncan be as low as -2,147,483,648, and one test uses exactly that value. Multiplying byxonce for every unit ofnwould be over two billion multiplications. The number of multiplications has to grow far more slowly thanndoes.Hint 2: Ask a smaller question
Suppose you have already worked out
xto the power 4. What is the smallest number of extra multiplications that gets youxto the power 8? And from there to the power 16?Hint 3: Name the pattern
nis too large to count through, but squaring the base lets you halve the exponent. In binary (0s and 1s only), halving removes the last digit ofn. A 1 means odd: one copy of the base goes to the answer first. Handlingnone digit per round is digit-by-digit arithmetic. The method's usual name is exponentiation by squaring. Read the lesson on digit-by-digit arithmetic.Hint 4: State the invariant
One product never changes: the answer times the base raised to the exponent that is left. It starts as the result you want, with the answer at 1. Each round moves value out of the exponent and into the answer or the base. When the exponent left is 0, the answer is the whole result.
Hint 5: Sketch the pseudocode
exponent =
nwithout its sign. base =x, or 1 /xwhennis negative. answer = 1. While exponent > 0: if exponent is odd, answer = answer × base. Then base = base × base, and exponent = exponent ÷ 2 rounded down. Return answer.
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
Approach
Repeatedly square the base and halve the exponent. Negative exponents use the reciprocal; avoid bitwise truncation for the minimum signed integer.
The slow way
Start at 1 and multiply by x, or by 1 / x when n is negative, once for every unit of n. It is correct, but one test has n = -2,147,483,648. That is over two billion multiplications, which takes seconds in JavaScript and far longer in Python. The method below needs 32 rounds.
The insight
Ten copies of x multiplied together are five copies of x × x. So squaring the base lets you halve the exponent. An odd exponent has one copy without a partner: multiply that copy into the answer, then halve what is left. Halving reaches 0 fast: an exponent of 2,147,483,648 is gone after 32 rounds.
Step by step
- Use the size of n; a negative n turns the base into 1 / x. The size of n is n without its sign. A negative power is 1 divided by the positive power, which equals 1 / x, called the reciprocal of x, raised to that positive power.
- Start the answer at 1. Multiplying by 1 changes nothing, so 1 is the neutral start for a product. It is also the final answer when n is 0, because the loop then never runs.
- Go on while some of the exponent is left. One product stays the same all the way: the answer times the base raised to the exponent left. It starts as the result you want, and every round keeps it while the exponent shrinks.
- Odd exponent: multiply the answer by the base once. An odd number of copies cannot all be paired. One copy moves into the answer, which leaves an even number. Odd or even is the exponent's last digit in binary, the notation that uses only 0s and 1s.
- Square the base and halve the exponent, rounding down. Each pair of copies becomes one copy of the squared base, so half as many are needed. Rounding down drops the single copy that an odd exponent has already given to the answer.
- No exponent is left: the answer is x to the power n. The product that never changed is now the answer times the base to the power 0, and anything to the power 0 is 1. So the answer alone is the result.
The same numbered steps are the comments in each solution.
JavaScript
function solve(x, n) {
// 1. Use the size of n; a negative n turns the base into 1 / x
let power = Math.abs(n);
let base = n < 0 ? 1 / x : x;
// 2. Start the answer at 1
let result = 1;
// 3. Go on while some of the exponent is left
while (power > 0) {
// 4. Odd exponent: multiply the answer by the base once
if (power % 2 === 1)
result *= base;
// 5. Square the base and halve the exponent, rounding down
base *= base;
power = Math.floor(power / 2);
}
// 6. No exponent is left: the answer is x to the power n
return result;
}TypeScript
function solve(x: number, n: number): number {
// 1. Use the size of n; a negative n turns the base into 1 / x
let power = Math.abs(n);
let base = n < 0 ? 1 / x : x;
// 2. Start the answer at 1
let result = 1;
// 3. Go on while some of the exponent is left
while (power > 0) {
// 4. Odd exponent: multiply the answer by the base once
if (power % 2 === 1) result *= base;
// 5. Square the base and halve the exponent, rounding down
base *= base;
power = Math.floor(power / 2);
}
// 6. No exponent is left: the answer is x to the power n
return result;
}
Python
def solve(x, n):
# 1. Use the size of n; a negative n turns the base into 1 / x
power = abs(n)
# float(x) turns a whole number into a float, the kind of number JavaScript
# uses here, so both languages do the same arithmetic.
base = 1 / x if n < 0 else float(x)
# 2. Start the answer at 1
result = 1.0
# 3. Go on while some of the exponent is left
while power > 0:
# 4. Odd exponent: multiply the answer by the base once
if power % 2 == 1:
result *= base
# 5. Square the base and halve the exponent, rounding down
base *= base
power //= 2
# 6. No exponent is left: the answer is x to the power n
return result
Example 1, traced
Input x = 2 n = 10 Output 1024
| Exponent left | Base | Is the exponent odd? | Answer | Square and halve |
|---|---|---|---|---|
| 10 | 2 | No: the answer stays 1 | 1 | Base 4, exponent 5 |
| 5 | 4 | Yes: 1 × 4 | 4 | Base 16, exponent 2 |
| 2 | 16 | No: the answer stays 4 | 4 | Base 256, exponent 1 |
| 1 | 256 | Yes: 4 × 256 | 1024 | Base 65536, exponent 0 |
| 0 | 65536 | Nothing is left: the loop ends | 1024 | Return 1024 |
Why it works
The answer times the base raised to the exponent left never changes. In example 1 it reads 1 × 2¹⁰, then 1 × 4⁵, 4 × 16², 4 × 256¹ and 1024 × 65536⁰: always 1024. An odd round moves one copy of the base into the answer, and squaring while halving regroups the rest. At exponent 0 only the answer remains.
Time and space
Time O(log |n|), extra space O(1). Every round halves the exponent. The number of halvings it takes to use a number up is about its logarithm, log for short, so the loop runs O(log |n|) times, where |n| is n without its sign: 32 rounds at most. Three numbers are stored, so the space is O(1).
n and m are input sizes, h is a tree's height, V and E are a graph's vertices and edges. The bounds describe this reference solution.
Watch out
- Deal with a negative
nbefore the loop. If the loop runs onnitself, a negative exponent is never above 0, the loop does not start, and 2 to the power -2 comes back as 1 instead of 0.25. - Round the halved exponent down. With plain division 5 becomes 2.5, and no later value is a whole odd number, so nothing more reaches the answer: 2 to the power 10 comes out as 4.
- In JavaScript, halve with Math.floor, not >>. The shift only handles whole numbers up to 2147483647: 2147483648 >> 1 is -1073741824, and the loop ends after one round. 2 to the power -2147483648, which rounds to 0, then returns 1.
Pattern
Digit-by-digit arithmetic. Builds on Binary Search and Happy Number.
Keep going
4 more problems solved with digit-by-digit arithmetic
- Add Two NumbersMedium
- Plus OneEasy
- Multiply StringsMedium
- Reverse IntegerMedium