快速幂取模详解与拓展

紫书上同余与模算术一节关于此问题一笔带过,讲的不是很详细。

本文原创,转载请注明出处 。:)

问题定义:

数论中经常出现的一个问题是对一个数的幂取模,也称为模取幂,即求a^b mod n。如果计算量较小,可以直接计算出a^b的值,再作模n运算。但是如果a和b的值都非常大,a^b的值用计算机难以表示,或者即使可以用大数运算的方式用计算机表示,也会因为耗时过长难以应用。基于模运算的基本性质,可以设计出一种算法,快速求解这一问题。这种方法为“快速幂取模”,也称为“反复平方法“。

 

利用公式a*b%n=((a%n)*b)%n=((a%n)*(b%n))%n,可以先解决a^b可能太大存不下的问题

d=ab mod n=(…((((a mod n)*a)mod n)*a)mod n…*a)mod n    {共b个a}

 由此可以引出一个迭代式

         d=a;

         for i=2 to b do  d=d mod n*a;

         d=d mod n;

 时间复杂度为O(b),当b很大时,效率很低。

设b(i)指的是二进制下b的第i位,比如当b=13时,其二进制为1101,则b(2)表示0,b(1)表示1

b = b(k) * 2^k + b(k-1)*2^(k-1) + ... + b(1) * 2^1 +b(0)*2^0 

那么

a ^ b = a ^ (b(k)*2^k + b(k-1)*2^(k-1) + ... + b(1)*2 + b(0) )

         = [a ^ (b(k)*2^k)]  * [a^(b(k-1)*2^(k-1))] *...*[a^(b(1)*2) ]* a

         = p(k) * p(k-1) * ... * p(1) * p(0)

其中,p(i)=a ^ (b(i)*2^i),b(i)=1或是0,则p(i)=a ^ (2^i) 或者 p(i) = 1

注意,p(i)可以一步一步的由前一个生成,即当p(i)=a ^ (2^(i-1)*2*b(i)),当p(i-1)!=0,b(i)!=0时,p(i)=p(i-1)*2

那么此时结合公式a*b%n=((a%n)*b)%n

p(i)%n=((p(i-1)%n)*b)%n

 

a ^ b % n =( p(k) * p(k-1) * ... * p(1) * p(0) )%n

     =(…((((p(k) mod n)*p(k))mod n)*p(k-1))mod n…*p(0))mod n 

结合上述迭代式,得到如下算法:

int PowerMod(int a, int b, int c)
{
int ans = 1;
a = a % c;
while(b>0) {
if(b % 2 == 1)
ans = (ans * a) % c;
b = b/2;
a = (a * a) % c;
}
return ans;
}

 

posted @ 2015-05-14 20:53  ACBingo  阅读(1260)  评论(0编辑  收藏  举报