您的位置:首页 > 其它

快速求幂算法

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

[cpp] view
plaincopy

int pow(int x, int n){

int result = 1;

while (n != 0){

result = result *x;

n = n -1;

}

return result;

}

通过使用如上的程序,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

int pow2(int x, int n){

if (n == 1) return x;

if (n == 0) return 1;

else if (n & 1)

return pow2(x, n/2) * pow2(x, n/2) * x;

else

return pow2(x, n/2) * pow2(x, n/2);

}

网上也有另外一种写法:

[cpp] view
plaincopy

int pow2(int x, int n){

if (n == 1) return x;

if (n == 0) return 1;

else if (n & 1)

return pow(x * x, n >>1)*x; //不同之处

else

return pow(x *x, n>>1); //不同之处

}

其实,这两种写法是相同,君不见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

int pow3(int x, int n)

{

int result = 1;

while (n > 0) {

if (n & 1) // n & 1 等价于 (n % 2) == 1

result *= x;

x *= x;

n >>= 1; // n >>= 1 等价于 n /= 2

}

return result;

}

程序运行良好,结果与上面的两个程序的结果相同,但是时间不知道要比上面的递归程序快多少倍呢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: