[数论] Miller_Rabbin算法判断大素数,Pollard_rho算法进行质因素分解

来源:互联网 发布:闲鱼拒收淘宝怎么判 编辑:程序博客网 时间:2024/05/13 13:54

讲解转载于:http://www.cnblogs.com/rainydays/archive/2011/09/01/2162049.html   http://blog.sina.com.cn/s/blog_86a9d97201015cj7.html

Miller-rabin

Miller-rabin算法是一个用来快速判断一个正整数是否为素数的算法。它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) mod p恒等于1。也就是对于所有小于p的正整数a来说都应该复合a^(p-1) mod p恒等于1。那么根据逆否命题,对于一个p,我们只要举出一个a(a<p)不符合这个恒等式,则可判定p不是素数。Miller-rabin算法就是多次用不同的a来尝试p是否为素数。

但是每次尝试过程中还做了一个优化操作,以提高用少量的a检测出p不是素数的概率。这个优化叫做二次探测。它是根据一个定理:如果p是一个素数,那么对于x(0<x<p),若x^2 mod p 等于1,则x=1或p-1。逆否命题:如果对于x(0<x<p),若x^2 mod p 不等于1,则p不是素数。根据这个定理,我们要计算a^(p-1) mod p是否等于1时,可以这样计算,设p-1=(2^t) * k。我们从a^k开始,不断将其平方直到得到a^(p-1),一旦发现某次平方后mod p等于1了,那么说明符合了二次探测定理的逆否命题使用条件,立即检查x是否等于1或p-1,如果不是则可直接判定p为合数。

pollard-rho

这是一个用来快速对整数进行质因数分解的算法,需要与Miller-rabin共同使用。求n的质因子的基本过程是,先判断n是否为素数,如果不是则按照一个伪随机数生成过程来生成随机数序列,对于每个生成的随机数判断与n是否互质,如果互质则尝试下一个随机数。如果不互质则将其公因子记作p,递归求解p和n/p的因子。如果n是素数则直接返回n为其素因子。

至于这个随机数序列是如何生成的暂时还不能理解,而且也是有多种不同的方式。这个序列生成过程中会产生循环,遇到循环则立即退出。

Pollard rho算法的原理就是通过某种方法得到两个整数a和b,而待分解的大整数为n,计算p=gcd(a-b,n),直到p不为1,或者a,b出现循环为止。然后再判断p是否为n,如果p=n成立,那么返回n是一个质数,否则返回p是n的一个因子,那么我们又可以递归的计算Pollard(p)和Pollard(n/p),这样,我们就可以求出n的所有质因子。
    具体操作中,我们通常使用函数x2=x1*x1+c来计算逐步迭代计算a和b的值,实践中,通常取c为1,即b=a*a+1,在下一次计算中,将b的值赋给a,再次使用上式来计算新的b的值,当a,b出现循环时,即可退出进行判断。
    在实际计算中,a和b的值最终肯定一出现一个循环,而将这些值用光滑的曲线连接起来的话,可以近似的看成是一个ρ型的。
    对于Pollard rho,它可以在O(sqrt(p))的时间复杂度内找到n的一个小因子p,可见效率还是可以的,但是对于一个因子很少、因子值很大的大整数n来说,Pollard rho算法的效率仍然不是很好,那么,我们还得寻找更加的方法了。


Miller-rabin算法用到了二次探测,因为有些数称为Carmichael数,它满足费马小定理,但不是素数。


模板:POJ  1811

[cpp] view plaincopy
  1. #include <iostream>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <algorithm>  
  6. #include <vector>  
  7. #include <queue>  
  8. #include <stack>  
  9. #include <map>  
  10. #include <set>  
  11. #include <cmath>  
  12. #include <time.h>  
  13. #include <iomanip>  
  14. #include <cctype>  
  15. using namespace std;  
  16.   
  17. /** 
  18. Miller_Rabin 算法进行素数测试 
  19. 快速判断一个<2^63的数是不是素数,主要是根据费马小定理 
  20. */  
  21. #define ll long long  
  22. const int S=8; ///随机化算法判定次数  
  23.   
  24. ///计算ret=(a*b)%c  a,b,c<2^63  
  25. ll mult_mod(ll a,ll b,ll c)  
  26. {  
  27.     a%=c;  
  28.     b%=c;  
  29.     ll ret=0;  
  30.     ll temp=a;  
  31.     while(b)  
  32.     {  
  33.         if(b&1)  
  34.         {  
  35.             ret+=temp;  
  36.             if(ret>c)  
  37.                 ret-=c;//直接取模慢很多  
  38.         }  
  39.         temp<<=1;  
  40.         if(temp>c)  
  41.             temp-=c;  
  42.         b>>=1;  
  43.     }  
  44.     return ret;  
  45. }  
  46.   
  47. ///计算ret=(a^n)%mod  
  48. ll pow_mod(ll a,ll n,ll mod)  
  49. {  
  50.     ll ret=1;  
  51.     ll temp=a%mod;  
  52.     while(n)  
  53.     {  
  54.         if(n&1)  
  55.             ret=mult_mod(ret,temp,mod);  
  56.         temp=mult_mod(temp,temp,mod);  
  57.         n>>=1;  
  58.     }  
  59.     return ret;  
  60. }  
  61.   
  62. ///通过费马小定理 a^(n-1)=1(mod n)来判断n是否为素数  
  63. ///中间使用了二次判断,令n-1=x*2^t  
  64. ///是合数返回true,不一定是合数返回false  
  65. bool check(ll a,ll n,ll x,ll t)  
  66. {  
  67.     ll ret=pow_mod(a,x,n);  
  68.     ll last=ret;//记录上一次的x  
  69.     for(int i=1;i<=t;i++)  
  70.     {  
  71.         ret=mult_mod(ret,ret,n);  
  72.         if(ret==1&&last!=1&&last!=n-1)  
  73.             return true;//二次判断为是合数  
  74.         last=ret;  
  75.     }  
  76.     if(ret!=1)  
  77.         return true;//是合数,费马小定理  
  78.     return false;  
  79. }  
  80.   
  81.   
  82. ///Miller_Rabbin算法  
  83. ///是素数返回true(可能是伪素数),否则返回false  
  84. bool Miller_Rabbin(ll n)  
  85. {  
  86.     if(n<2) return false;  
  87.     if(n==2) return true;  
  88.     if((n&1)==0) return false;//偶数  
  89.     ll x=n-1;  
  90.     ll t=0;  
  91.     while((x&1)==0)  
  92.     {  
  93.         x>>=1;  
  94.         t++;  
  95.     }  
  96.     srand(time(NULL));  
  97.     for(int i=0;i<S;i++)  
  98.     {  
  99.         ll a=rand()%(n-1)+1; // 生成随机数 0<a<=n-1  去试试  
  100.         if(check(a,n,x,t))  
  101.             return false;  
  102.     }  
  103.     return true;  
  104. }  
  105.   
  106. /** 
  107. pollard_rho算法进行质因素分解 
  108. */  
  109. ll factor[100];//质因素分解结果(一开始无序)  
  110. int tot;//质因素的个数 0~to-1  
  111. ll gcd(ll a,ll b)  
  112. {  
  113.     ll t;  
  114.     while(b)  
  115.     {  
  116.         t=a;  
  117.         a=b;  
  118.         b=t%b;  
  119.     }  
  120.     if(a>=0) return a;  
  121.     return -a;  
  122. }  
  123.   
  124. ///找到一个质因素  
  125. ll pollard_rho(ll x,ll c)  
  126. {  
  127.     ll i=1,k=2;  
  128.     srand(time(NULL));  
  129.     ll x0=rand()%(x-1)+1;//随即一个因子来判断  
  130.     ll y=x0;  
  131.     while(1)  
  132.     {  
  133.         i++;  
  134.         x0=(mult_mod(x0,x0,x)+c)%x;  
  135.         ll d=gcd(y-x0,x);  
  136.         if(d!=1&&d!=x) return d;  
  137.         if(y==x0) return x;  
  138.         if(i==k)  
  139.         {  
  140.             y=x0;  
  141.             k+=k;  
  142.         }  
  143.     }  
  144. }  
  145.   
  146. ///对n进行质因素分解,存入factor数组,k为了防止死循环,设置为107左右  
  147. void findfac(ll n,int k)  
  148. {  
  149.     if(n==1)  
  150.         return;  
  151.     if(Miller_Rabbin(n))  
  152.     {  
  153.         factor[tot++]=n;  
  154.         return;  
  155.     }  
  156.     ll p=n;  
  157.     int c=k;  
  158.     while(p>=n)  
  159.         p=pollard_rho(p,c--);  
  160.     findfac(p,k);  
  161.     findfac(n/p,k);  
  162. }  
  163.   
  164. int main()  
  165. {  
  166.     int t;scanf("%d",&t);  
  167.     ll n;  
  168.     while(t--)  
  169.     {  
  170.         scanf("%I64d",&n);  
  171.         if(Miller_Rabbin(n))  
  172.         {  
  173.             printf("Prime\n");  
  174.             continue;  
  175.         }  
  176.         tot=0;  
  177.         findfac(n,107);  
  178.         sort(factor,factor+tot);  
  179.         printf("%I64d\n",factor[0]);  
  180.     }  
  181.     return 0;  
  182. }  
0 0
原创粉丝点击