传统幂运算
幂运算应该说是一种很简单的运算,在计算机中,可以通过循环手段实现。要计算$n^m$,需要进行m-1次乘法运算,所以时间复杂度为O(m)。
1 #include <iostream> 2 #define LL long long 3 using namespace std; 4 5 LL pow(LL base,LL pow){ 6 LL res = base; 7 for(int i=1;i<pow;i++) 8 res*=base; 9 return res; 10 }
快速幂的原理
当m较小时,O(m)的算法完全可以满足我们的要求,可是当m较大时,幂运算就可能无法满足我们的要求了。挑剔的计算机科学家想到,能不能在传统的幂运算上进一步优化呢?他们还真想到了办法,首先,幂运算在指数层面,执行的是加法运算,例如,计算$2^1000$,它的计算步骤是
$$2^{1} = 2^{0+1}\\ 2^{2} = 2^{1+1}\\2^{3} = 2^{2+1}\\...\\2^{1000} = 2^{999+1}$$
也就是说,$n^m$中的m,是在从0开始,逐步自增,最终达到m的。那么如果为这个自增过程加速,那么就可以降低整个算法的时间复杂度了。那么怎么增加速度呢,科学家们想到了用二进制做文章。我们可以将一个数转化为一个二进制,例如:
$$97 =(1100001)_2$$
在二进制中,一位上的数为1,代表该数存在对应的二进制整数,为0则不存在
$$97 = (1100001)_2 = 64+32+1 = (1000000)_2+(100000)_2+(1)_2$$
根据这种特征,科学家创造出了快速幂算法:
首先将指数m转化为二进制:
$$1000 = (1111101000)_2$$
则原值可以表示为:
$$2^{1000} = 2^{(1111101000)_2}$$
然后不断改变底数,就是不断让它和自己相乘:
$$2^1 = 2^{(1)_2}\\ 2^2 = 2^1*2^1=2^{(10)_2}\\2^4 = 2^2*2^2 = 2^{(100)_2}\\...$$
当底数自增时,每一次都判断当前这个数对应的指数在指数m的二进制表示中是否存在,如果存在,这将该底数和当前结果相乘,否则忽略。
代码如下:
#include<iostream> #define LL long long using namespace std; LL mod = 1000; LL fastPow(LL base,LL pow) { LL res = 1; while(pow) { if(pow%2) res = (res*base)%mod; base =(base*base)%mod; pow/=2; } return res; } int main() { LL c = fastPow(2,1000000000); printf("%lld",c); return 0; }
浙公网安备 33010602011771号