模幂函数 (将网上搜到的大作,做个整理解释给咱菜鸟看,,,,呵呵)

来源:互联网 发布:田众和时代网络 编辑:程序博客网 时间:2024/05/22 09:51


由于矩阵乘法具有结合律,因此A^4 = A * A * A * A = (A*A) * (A*A) = A^2 * A^2。我们可以得到这样的结论:当n为偶数时,A^n = A^(n/2) * A^(n/2);当n为奇数时,A^n = A^(n/2) * A^(n/2) * A (其中n/2取整)。这就告诉我们,计算A^n也可以使用二分快速求幂的方法。例如,为了算出A^25的值,我们只需要递归地计算出A^12、A^6、A^3的值即可。根据这里的一些结果,我们可以在计算过程中不断取模,避免高精度运算。

在Miller Rabbin测试素数这篇文章里的Modular_Exp函数里,就用到了快速幂取模的思想。
这里总结下。
求a^b%c(这就是著名的RSA公钥的加密方法)
当a,b很大时,直接求解这个问题不太可能
你能想到哪些优化呢?
算法1:直观上,也许最容易想到的是利用a*b%c=((a%c)*b)%c,这样每一步都进行这种处理,这就解决了a^b可能太大存不下的问题,但这个算法的时间复杂度依然是O(n),根本没有得到优化。当b很大时运行时间会很长
算法2:另一种算法利用了二分的思想,可以达到O(logn)。
可以把b按二进制展开为b=p(n)*2^n+p(n-1)*2^(n-1)+…+p(1)*2+p(0)    (可用>>=移位来判断每一位,计算下边的每一项)
其中p(i) (0<=i<=n)为0或1
这样a^b=a^(p(n)*2^n+p(n-1)*2^(n-1)+...+p(1)*2+p(0))
=a^(p(n)*2^n)*a^(p(n-1)*2^(n-1))*...*a^(p(1)*2)*a^p(0),,,,,,,,,,,,,,,,,,,,(1)
对于p(i)=0的情况,a^p(i)*2^(i-1)=a^0=1,不用处理
我们要考虑的仅仅是p(i)=1的情况
a^(2^i)=(a^(p(i)*2(i-1)))^2
利用这一点,我们可以递推地算出所有的a^(2^i)
当然由算法1的结论,我们加上取模运算a^(2^i)%c=((a^(2(i-1))%c)*a^(2(i-1)))%c((1)中的每一项,即a^b%n)

而上边还不够简练,a^2^i=a*a*a,,,,,所以a^2^3%c=((a*a)%c*(a*a)%c)*%c*((a*a)%c*(a*a)%c)%c,,,,,yi以此类推,刚好是一个循环t=(t*t)%c;

于是再把所有满足p(i)=1的a^(2^i)%c按照算法1乘起来再%c就是结果(公式 :(x*y)%z=((x%z)*(y%z))%z  )
即二进制扫描从最高位一直扫描到最低位。


 

在随机素数测试算法中要用到模幂运算,在O(lgn)的时间内产生模幂结果是非常有用的。
在诸如RSA等算法中都要用到求a^n mod p的运算,例如费马小定理(a^(n-1) mod n = 1,p是a的非素数因子)
及rsa算法用到的费马定理的推广(a^(y(n))mod n = 1,y(n)为n的欧拉函数)等等都需要用到模幂运算,那么
怎么能快速的到模幂运算结果其实原理很简单,这是我用english写的,希望没写错,呵呵
Basing on the two simple theories:
 1,(x*y)%z=((x%z)*(y%z))%z
 2,(x^y)%z=((x%z)^y)%z
To solve the y=(g^x)%p problem left shifting x until x become 0,compute g^x by computing
k=(g^(x/2)%p) and g^x=k*k or g^x=k*k*g 。so this algorithm is O(lgn) which is also linear。
This is a simple and recursive algorithm.
这是我写的参考程序 (仅供参考)
class MMath{
 
 public:
  
 static int power(int g,int p,int n){

  int s,u;

  if(n==0)return 1;
  else {
   s = power(g,p,n>>1);
   u = s*s;
   if(n%2==0)
    return u%p;
   else
    return u*g%p;
  }
 }

 static bool prime_judge(int n){
  if(power(2,n,n-1)!=1)return false;
  else return true;
 }
}
另外附一个根据费马定理写的素数测试程序(会产生错误,伪素数如1387等)
MillerRabin测试还没有想好怎么写程序呢。

原创粉丝点击