I am currently reading Skiena\'s \"The Algorithm Design Manual\".
He describes an algorithm for calculating the power of a number i.e. calculate a^n
.
The concept is simple. For example, compute the value of 38
You can use the obvious way which is 38 = 3 x 3 x 3 x 3 x 3 x 3 x 3 x 3 which takes 7 multiplication operations. Or there is a better way.
Let say that
Going backward, it only takes 3 multiplication to compute 38 instead of 7
Here is the clearly view of the process:
32 = 3 x 3 = 9 34 = 32 x 32 = 9 x 9 = 81 38 = 34 x 34 = 81 x 81 = 6,561
Then, there is another problem, what if the power is odd number. For example: 39, how to deal with it? You can either do this
39 = 3 x 38 or 39 = 3 x 34 x 34
Lets call the algorithm that continuously multiple the number as Method A, and algorithm that continuously divide the power by two as Method B. How good is method A comparing to method B? For a small number such as 38, there is not much significant improvement, even those, we minimize the number of multiplication, but we also slightly increase the number of division operation.
So for 38
Multiplication Division Method A: 7 0 Method B: 3 3
However, for the larger power, for example: 34,294,967,296
Multiplication Division Method A: 4,294,967,295 0 Method B: 32 32
The difference is huge.
x = power(a, n/2)
will give you a^n/2. If even this whole statement is squared giving (a^n/2)^2. Now if n is odd, during n/2 a power of a^1 is lost so to get it back it is multiplied with a. This is according to the equation given.
The function power(...)
appears to be written the way it is to handle the effects of integer division. Recall that under integer division rules, the fractional part is discarded. This will only affect odd integers since an even integer divided by two produces no remainder.
Thus whenever n
is an even integer, the value computed for n/2
is exactly equal to n/2
and the top branch of the if
can be taken: this is exactly what the equations stipulate.
Whenever n
is an odd integer, the value computed for n/2
is actually equal to floor(n/2)
. In other words, the statement:
x = power(a,n/2)
Has actually computed the result
x = power(a,(n-1)/2)
Meaning that you have permanently lost one 1 from your exponent, and simply returning x^2
will be short one power of a
. Hence the bottom branch, which adds back in the power of a
.
If you imagine that instead of integer division, the computer was capable of perfectly lossless real number division, then you could rewrite the function as:
function power( a, n )
if (n = 0)
return(1)
x = power(a,n/2)
return x^2
You can easily satisfy yourself that this is a simple recursive implementation of the second equation you provided in the question.
This formula a^n = ((a^n/2)^2)
, which you understand dictates recursive algorithm.
To get a^n
you need first to calculate a^(n/2)
,
To get a^(n/2)
, you need to calculate a^((n/2)/2)
,
... and so on, until (n/2/2/...2)
reaches 0, which is the termination condition of the recursion.
So, the recursive algorithm follows that formula exactly :
to get power(a,n)
you first recursively calculate power(a,n/2)
and then return the result adjusting for n
being odd/even number.
There is also wikipedia article about this implementation.
This function is recursive, meaning that when called, it is going to call itself over and over again until some final condition is met. In this case, there are three final conditions that will stop the function from calling itself and return the result.
If I were you I would try to apply the algorithm manually on a couple of different values in order to understand.
First of all, let's fix your algorithm:
function power( a, n )
if (n = 0)
return(1)
x = power(a,n/2)
if (n is even)
return(x*x)
else
return(a*x*x)
Say you want to calculate power(2,8)
, that is, 2^8
(^
is not XOR
here, of course).
1) (a=2
, n=8
). 2^8 = (2^4)^2
, so we have to calculate x=2^4
, and then x*x
to yield the final result. We have to call power()
again to get x
. power(2,4)
.
2) (a=2
, n=4
). 2^4 = (2^2)^2
, so we have to calculate x=2^2
, and then x*x
to yield the final result. We have to call power()
again to get x
. power(2,2)
.
3) (a=2
, n=2
). 2^2 = (2^1)^2
, so we have to calculate x=2^1
, and then x*x
to yield the final result. We have to call power()
again to get x
. power(2,1)
.
4) (a=2
, n=1
). 2^1 = (2^0)^2
, so we have to calculate x=2^0
, and then a*x*x
to yield the final result. We have to call power()
again to get x
. power(2,0)
.
5) (a=2
, n=0
). 2^0 = 1
because n
is 0
, so we have the value of x
that is returned to step #4.
4) (a=2
, n=1
, x=1
). The final result for this step is a*x*x = 2*1*1=2
, which is the value to be assigned to x
in step #3.
3) (a=2
, n=2
, x=2
). The final result for this step is x*x = 2*2 = 4
. This is the result to be assigned to x
in step #2.
2) (a=2
, n=4
, x=4
). The final result for this step is x*x = 4*4 = 16
. This is the result to be assigned to x
in step #1.
1) (a=2
, n=8
, x=16
). The final result for this step is x*x = 16*16 = 256
. This is the result to be returned by power(2,8)
.