Have a look at the following code to find X^y.
/* Find exponent in logarithmic complexity */
int findPower(int base, exponent){
if( 1 == exponent ) return base;
return (findPower(base, exponent/2)*findPower(base, exponent-exponent/2));
}
int main(int argc, char *argv[]){
if(argc < 3) {
printf("Usage :: logpow baseNumber power\n");
return -1;
}
printf("%s ^ %s = %d\n", argv[1], argv[2], findPow( atoi(argv[1]),
atoi(argv[2])) );
return 0;
}
Analysis shows that this has a complexity of theta(log(n)).
But I ran it to measure time, and here are the results
Run 1: (calculating 1^500_million)
user-lm Programming # time ./a.out 1 500000000
1 ^ 500000000 = 1
real 0m5.009s
user 0m5.000s
sys 0m0.000s
Run 2: (calculating 1^1_Billion)
user-lm Programming # time ./a.out 1 1000000000
1 ^ 1000000000 = 1
real 0m9.667s
user 0m9.640s
sys 0m0.000s
Run 3: (calculating 1^2_Billion)
user-lm Programming # time ./a.out 1 2000000000
1 ^ 2000000000 = 1
real 0m18.649s
user 0m18.630s
sys 0m0.000s
From above we can see that the actual time complexity has linear behaviour rather than logarithmic!
What could be the reason for such a huge difference in complexity?
Regards,
Microkernel
You are actually invoking 2 function calls from each call. The recursion tree would be a binary tree of height
log(exponent), so the number of nodes in it will be2^log(exponent) == exponent. So overall it becomes a linear algorithm. You can rewrite it like this for better performance:The trick is, you have to store the value of
findPower(base, exponent/2)to get the logarithmic complexity. The recursion tree still has heightlog(exponent)but each node has only one child now, so there would belog(exponent)nodes. If you actually call it twice it will degrade the performance even more than a linear one. There’s no need to calculate the same value second time if you already have that!As @David Schwartz pointed out, the number of calls made in your code would be doubled if
exponentis doubled. But when you save the values, doubling theexponentmake only one more call.