快速幂的学习

来源:互联网 发布:mac投影仪只显示桌面 编辑:程序博客网 时间:2024/06/06 02:51

莫名的看到了快速幂,发现很多地方都需要用到这个东西,于是决定学一学

在此之前先回忆一个定理    (a*b)mod n 可以转换为  (a mod n)*(b mod n)mod n

最主要的原理就是把指数拆成2进制然后再乘   这样可以大大减少乘的次数  原本计算幂函数的复杂度是O(N),现在就变成了O(Log N)


本身的快速幂也是很简单的,就是拆成二进制做乘法就可以了

代码:

int fpow(int a,int b)

{

int ans=1;

while(b>0)

{

if(b&1!=0)ans*=a;//二进制下当前的最右位判断是不是1

a*=a; //平方后供下一次乘法使用

b>>=1; //下一位

}

return ans;

}

但是这个方法有一个弊端,就是幂函数计算出来的东西本身就是巨大,有可能连unsigned long long 都存不下,所以为了计算 (a*b)mod n,就要每乘一次就mod一次

这个是白书上的代码

long long mod_pow(long long x,long long n,long long mod)

{

long long res=1;

while(n>0)

{

if(n&1)res=res*x%mod;

x=x*x%mod;

n>>=1;

}

return ans;

}

这个可能就有点难理解了,而且我在网上看到的各种证明过程都不大适合我

于是我就自己举了个例子

比如要计算2^3 mod 3      根据原版的快速幂  应该是转换为 2^(2^0)*2^(2^1)mod 3

就是  (2^1 * 2^2) mod 3

根据一开始的定理,可以转换为  (2^1 mod 3 * 2^2 mod 3)mod 3

再来看源程序,如果最末尾是1,那么res 就乘上 x % mod

在例子中实际就是运算  2^1 mod 3 

然后下一句x=x*x%mod;  实际上就是在计算 2^2 mod 3

在下一个循环中判断是不是要乘上这个东西,如果末尾是1,乘上2^2 mod 3,然后再mod 3就是最后的那一步运算

期间有可能有一个疑问就是x的值被改变了之后,再平方取余不会错吗

因为这个二进制指数的幂函数,每一步算出来的就是上一步的平方,比如计算2 ^4 mod 3 ,由于x的值已经变成了2^2 mod 3,这里可能会认为

再执行这一步x=x*x%mod;就错了,实际上 2^4 mod 3 == (2^2*2^2)mod 3 == (2^2 mod 3 * 2^2 mod 3)mod 3 刚刚好

还有一个可能的疑问就是 如果上面计算的时候不是最后一步但还是mod了,其实这个是没有关系的, 因为前面乘x的时候已经mod了,所以后面

再mod 他的值也不会变。

至此,疑惑都解释清了,感觉自己对mod运算的理解更深了一步

原创粉丝点击