快速冪取模算法

文章出處:http://blog.csdn.net/lsldd/article/details/5506933

參考文章來源:Reait  Home(http://www.reait.com/blog.html) 轉載請註明,謝謝合作。 

在Miller Rabbin測試素數,就用到了快速冪取模的思想。這裏總結下。
求a^b%c(這就是著名的RSA公鑰的加密方法),當a,b很大時,直接求解這個問題不太可能 
算法1:利用公式a*b%c=((a%c)*b)%c,這樣每一步都進行這種處理,這就解決了a^b可能太大存不下的問題,但這個算法的時間複雜度依然沒有得到優化
代碼如下:

[cpp] view plain copy
  1. int modexp_simple(int a,int b,int n)       
  2. {      
  3.     int ret = 1;  
  4.     while (b--)  
  5.     {  
  6.         ret = a * ret % n;  
  7.     }  
  8.     return ret;  
  9. }    
算法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)
對於p(i)=0的情況, a^(p(i) * 2^(i-1) ) =  a^0  =  1,不用處理
我們要考慮的僅僅是p(i)=1的情況
化簡:a^(2^i)  = a^(2^(i-1)  * 2) = (  a^(  p(i)  *  2^(i-1)  )  )^2
(這裏很重要!!具體請參閱秦九韶算法:http://baike.baidu.com/view/1431260.htm
利用這一點,我們可以遞推地算出所有的a^(2^i)
當然由算法1的結論,我們加上取模運算:
a^(2^i)%c = ( (a^(2^(i-1))%c) * a^(2^(i-1)))  %c

於是再把所有滿足p(i)=1的a^(2^i)%c按照算法1乘起來再%c就是結果 即二進制掃描從最高位一直掃描到最低位

實例代碼:遞歸

[cpp] view plain copy
  1. //計算a^bmodn       
  2. int modexp_recursion(int a,int b,int n)       
  3. {      
  4.     int t = 1;  
  5.   
  6.     if (b == 0)  
  7.         return 1;  
  8.   
  9.     if (b == 1)  
  10.          return a%n;  
  11.   
  12.     t = modexp_recursion(a, b>>1, n);  
  13.   
  14.     t = t*t % n;  
  15.   
  16.     if (b&0x1)  
  17.     {      
  18.         t = t*a % n;  
  19.     }  
  20.   
  21.     return t;  
  22.  }   


實例代碼2:非遞歸優化 

[cpp] view plain copy
  1. #include <iostream>     
  2. using namespace std;     
  3.     
  4. //計算a^bmodn     
  5. int modexp(int a,int b,int n)     
  6. {     
  7.     int ret=1;     
  8.     int tmp=a;     
  9.     while(b)     
  10.     {     
  11.        //基數存在     
  12.        if(b&0x1) ret=ret*tmp%n;     
  13.        tmp=tmp*tmp%n;     
  14.        b>>=1;     
  15.     }     
  16.     return ret;     
  17. }     
  18.     
  19. int main()     
  20. {     
  21.     cout<<modexp(2,10,3)<<endl;     
  22.     return 0;     
  23. }    

 

原文:http://kmplayer.javaeye.com/blog/601578


發佈了87 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章