快速求幂算法

来源:互联网 发布:windows 7 mstsc 会话 编辑:程序博客网 时间:2024/04/25 14:57

我们知道在数学表达式中pow(x, n)表示求x^n的幂。一般情况下,如果我们要写一个程序的话,最简单的程序可能是这样的:

[cpp] view plaincopy
  1. int pow(int x, int n){  
  2.     int result = 1;  
  3.     while (n != 0){  
  4.         result = result *x;  
  5.         n = n -1;  
  6.     }  
  7.     return result;  
  8. }  

通过使用如上的程序,2^4 = 2 * 2 * 2 * 2,在程序中做了4-1=3次乘法,但是有没有更高效的算法来减少乘法的次数呢。

答案是肯定的。

我们知道

2^9 = 2^4 * 2^4 * 2

2^8 = 2^4 * 2^4

2^7 = 2^3 * 2^3 * 2

2^6 = 2^3 * 2^3

……

我们发现了什么?

x^n = x^(n/2) * x^(n/2) (n为偶数)

x^n = x^(n/2) * x^(n/2) * n (n为奇数);

这样的话我们就可以使用递归的方法将问题化为一半一半的解法。(divide and conquer)

程序如下:

[cpp] view plaincopy
  1. int pow2(int x, int n){  
  2.     if (n == 1) return x;  
  3.     if (n == 0) return 1;  
  4.     else if (n & 1)  
  5.         return pow2(x, n/2) * pow2(x, n/2) * x;       
  6.     else   
  7.         return pow2(x, n/2) * pow2(x, n/2);       
  8. }  
网上也有另外一种写法:

[cpp] view plaincopy
  1. int pow2(int x, int n){  
  2.     if (n == 1) return x;  
  3.     if (n == 0) return 1;  
  4.     else if (n & 1)   
  5.         return pow(x * x, n >>1)*x; //不同之处  
  6.     else   
  7.         return pow(x *x, n>>1); //不同之处  
  8. }  

其实,这两种写法是相同,君不见pow(x, n) * pow(x, n) = pow(x*x, n)

递归有很多好处,其中之一就是代码简洁,可读性强,但是也有不好的地方,如果n的位数足够大(假设整个结果不溢出的情况),那么其使用的栈可能会产生溢出的情况。

现在既然我们已经有了一个递归的方法,那么写一个非递归的方法就水到渠成了。我们要想想如何去写这个非递归的程序了。

例如2^9 = 2^(1001) 括号里面是二进制数制。在我们做2^9乘法的时候,我们是用这样的方法来乘的:2^9 = 2^8 * 2^1

也就是只有在二进制数位上为1时乘一个2^n,而在二进制数位上为0时,则不乘。那么我们的程序就有了:

[cpp] view plaincopy
  1. int pow3(int x, int n)  
  2. {  
  3.     int result = 1;  
  4.     while (n > 0) {  
  5.         if (n & 1)        // n & 1 等价于 (n % 2) == 1  
  6.             result *= x;  
  7.         x *= x;  
  8.         n >>= 1;        // n >>= 1 等价于 n /= 2  
  9.     }  
  10.     return result;  
  11. }  
程序运行良好,结果与上面的两个程序的结果相同,但是时间不知道要比上面的递归程序快多少倍呢!
原创粉丝点击