Topics › Bit Manipulation › Advanced Maths
Pow(x,n)
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
Implement pow(x, n): given a real number x and a 32-bit signed integer n, compute x raised to the power n. The exponent may be negative, in which case the answer is 1 / x^|n|. You may not call the library Math.pow; the point of the exercise is the algorithm, binary exponentiation, which is one of the most reused ideas in competitive programming (modular powers, matrix powers, fast Fibonacci).
Constraints: -100.0 < x < 100.0, -2^31 ≤ n ≤ 2^31 - 1, and either x != 0 or n > 0. Answers are compared with a tolerance of 10^-5; the tests in the Java file use a stricter relative tolerance of 10^-9.
Example 1
x = 2.0, n = 10
answer = 1024.0
Example 2
x = 2.0, n = -2
answer = 0.25 // 1 / 2^2
Example 3
x = 2.1, n = 3
answer = 9.261 // 2.1 * 2.1 * 2.1
Approach 1: Brute force
Intuition. Multiply x by itself |n| times, and if n is negative, take the reciprocal at the end. This is the definition of a power and is exactly right for small exponents. For n near 2^31 it performs two billion multiplications, which is both too slow and, as repeated rounding accumulates, less accurate than necessary.
Algorithm.
- Let
times = |n|, computed inlong. - Start with
result = 1.0and multiply byxtimestimes. - Return
1 / resultifn < 0, elseresult.
static double bruteForce(double x, int n) {
long times = Math.abs((long) n); // long: Math.abs(Integer.MIN_VALUE) stays negative in int
double result = 1.0;
for (long i = 0; i < times; i++) result *= x;
return n < 0 ? 1.0 / result : result;
}
Complexity. Time O(|n|). Space O(1).
Note the cast before Math.abs. Math.abs(Integer.MIN_VALUE) is Integer.MIN_VALUE (there is no positive counterpart in 32 bits), so an int version would loop zero times and return 1.0 for every x.
Approach 2: Better, recursive binary exponentiation
Intuition. Halve the problem instead of decrementing it. x^n = (x^(n/2))^2 when n is even, and x^n = (x^(n/2))^2 × x when n is odd (with integer division, so n/2 rounds down and the odd case supplies the missing factor). Each recursive call halves the exponent, so there are only about log2(n) levels. The one trap is to compute x^(n/2) once and square it; calling the function twice (pow(x, n/2) * pow(x, n/2)) doubles the work at every level and the running time collapses back to O(n).
Negative exponents are handled up front by replacing x with 1 / x and n with -n, done in long because -Integer.MIN_VALUE does not fit in an int.
Algorithm.
- Convert
nto alongexponent. If it is negative, setx = 1 / xand negate the exponent. powRecursive(x, 0) = 1.- Otherwise compute
half = powRecursive(x, n / 2)and returnhalf × half, timesxifnis odd.
static double better(double x, int n) {
long exponent = n; // long so that -Integer.MIN_VALUE is representable
if (exponent < 0) {
x = 1.0 / x;
exponent = -exponent;
}
return powRecursive(x, exponent);
}
private static double powRecursive(double x, long n) {
if (n == 0) return 1.0;
double half = powRecursive(x, n / 2);
return (n % 2 == 0) ? half * half : half * half * x;
}
Complexity. Time O(log n): the exponent halves on every call. Space O(log n) for the recursion stack, at most 32 frames here.
Approach 3: Optimal, iterative binary exponentiation
Intuition. Read the exponent in binary. For n = 10 = 1010₂, x^10 = x^8 × x^2: the set bits of n say which powers x^(2^k) to multiply together. Maintain a running base that is squared at every step (x, x^2, x^4, x^8, ...) and shift the exponent right one bit at a time; whenever the current lowest bit is 1, multiply the base into the result. This is the recursion unrolled into a loop: same O(log n) multiplications, no stack, and it is the form that generalises directly to modular arithmetic and matrix powers.
Algorithm.
- Convert
ntolong; if negative, replacexwith1 / xand negate the exponent. result = 1.0.- While
exponent > 0: ifexponent & 1is1,result *= x; thenx *= xandexponent >>= 1. - Return
result.
static double optimal(double x, int n) {
long exponent = n;
if (exponent < 0) {
x = 1.0 / x;
exponent = -exponent;
}
double result = 1.0;
while (exponent > 0) {
if ((exponent & 1) == 1) result *= x; // this bit of n is set, so x^(2^k) belongs in the answer
x *= x; // x^(2^k) -> x^(2^(k+1))
exponent >>= 1;
}
return result;
}
Dry run on x = 2.0, n = 10 (1010₂):
| exponent (binary) | lowest bit | result | x (after squaring) |
|---|---|---|---|
| 1010 | 0 | 1 | 4 |
| 101 | 1 | 1 × 4 = 4 | 16 |
| 10 | 0 | 4 | 256 |
| 1 | 1 | 4 × 256 = 1024 | 65536 |
| 0 | loop ends | 1024 |
The bases consumed were x^2 = 4 and x^8 = 256, exactly the set bits of 10. Four iterations instead of ten multiplications; for n = 2^31 - 1 it is 31 iterations instead of two billion.
Complexity. Time O(log n): one iteration per bit of n. Space O(1).
Why invert x first rather than the result at the end? Both are mathematically identical and both are fine in floating point for this problem. Inverting first keeps the loop oblivious to the sign, which matters when the same loop is reused for modular exponentiation (where “inverse” means a modular inverse and must be applied to the base).
Edge cases and pitfalls
n = Integer.MIN_VALUE.-noverflows inint, andMath.abs(n)returns a negative number. Both fast methods widen tolongbefore negating.pow(1.0, MIN_VALUE)is1.0,pow(2.0, MIN_VALUE)underflows to0.0, andpow(-1.0, MIN_VALUE)is1.0because the exponent is even.n = 0. Every method returns1.0, including forx = 0.0;0^0 = 1is the convention used by the judge and byMath.pow.x = 0with negativen. Division by zero in floating point givesInfinity, not an exception. The constraints rule this input out, but production code should decide what to return.- Negative base.
(-2)^3 = -8and(-2)^4 = 16; the sign falls out of the multiplications with no special handling. - Squaring twice in the recursion.
powRecursive(x, n/2) * powRecursive(x, n/2)is the classic mistake that makes the “fast” methodO(n). Store the half result in a variable. - Overflow of the result.
2^31 = 2147483648exceedsintrange but is an exactdouble. If the problem were about integers modulom, you would take% mafter every multiplication, inlong. - Precision. Binary exponentiation performs about
2 log nroundings versusnfor the loop, so it is more accurate as well as faster. Compare doubles with a tolerance, never with==.
Related problems
- Pow(x, n) is the recursion-step treatment of the same problem.
- Introduction to Bits and Tricks explains the
& 1and>>= 1operations that drive the iterative loop. - Check if a Number is Odd or Not is the bit test used to decide whether the current power contributes.
- Count the Number of Set Bits counts exactly how many multiplications into
resultthe loop performs.