base *= base;
Your problem lies with that statement, you should not be changing base
at all. Rather, you should be adjusting result
based on the constant value of base
.
To do powers, you need repeated multiplication, but the base *= base
gives you a repeated squaring of the value and you'll therefore get a much bigger value than desired. This actually works for powers of four since you iterate 4 - 2
times, squaring each iteration, and x4 == (x2)2
.
It will not work for higher powers like six since you iterate 6 - 2
times, and x6 != (((x2)2)2)2
. That latter value is actually equivalent to x16
.
As an aside (despite your contention), it's actually not guaranteed to work for powers of two. If you follow the code in that case, you'll see that result
is never assigned a value so the return value will be arbitrary. If it's working for you, that's accidental and likely to bite you at some point.
The algorithm you can use should be something like:
float power(float base, int exponent):
# 0^0 is undefined.
if base == 0 and exponent == 0:
throw bad_input
# Handle negative exponents.
if exponent < 0:
return 1 / power(base, -exponent)
# Repeated multiplication to get power.
float result = 1
while exponent > 0:
# Use checks to detect overflow.
float oldResult = result
result *= base
if result / base is not close to oldResult:
throw overflow
exponent -= 1
return result
This algorithm handles:
- negative integral exponents (since
x-y = 1/xy
);
- the undefined case of
00
; and
- overflow if you do not have arbitrary-precision values (basically, if
(x * y) / y != x
, you can be reasonably certain an overflow has occurred). Note the use of "not close to", it's unwise to check floats for exact equality due to potential for errors due to precision limits - far better to implement a "is close enough to" check of some description.
One thing to keep in mind when translating to C or C++, a 2's complement implementation will cause issues when using the most negative integer, since its negation is often the same value again again due to the imbalance between the positive and negative values. This is likely to lead to infinite recursion.
You can fix that simply by detecting the case early on (before anything else), with something like:
if INT_MIN == -INT_MAX - 1 and exp == INT_MIN:
throw bad_input
The first part of that detects a 2's complement implementation, while the second detects the (problematic) use of INT_MIN
as an exponent.