大素数测试和大数素因子分解

来源:互联网 发布:程序员女神 赵洁琼 编辑:程序博客网 时间:2024/06/09 18:56

小黄书第19章p82页根据合数的拉宾-米勒测试可得到素数的必要条件。

参考资料。

以POJ1811 Prime Test 为例。

#include<stdio.h>#include<math.h>#include<stdlib.h>#include<algorithm>using namespace std;typedef long long LL;const int S=20;LL pfact[10005],ant;LL multi_mod(LL a,LL b,LL c){ //防止a*b溢出!  LL ans=0;  while(b){    if(b&1){      ans=(ans+a)%c;    }    a<<=1;    if(a>=c)a%=c;    b>>=1;  }  return ans;}LL pow_mod(LL a,LL b,LL c){  LL ans=1;  while(b){    if(b&1){      ans=multi_mod(ans,a,c);    }    a=multi_mod(a,a,c);    b>>=1;  }  return ans;}bool check(LL a,LL n,LL x, LL t){  LL ret=pow_mod(a,x,n); // LL last=ret; if(ret==1||ret==n-1)return false;//根据合数的拉宾-米勒测试. 满足a^x和1不同余n的为合数.  for(int i=1;i<=t;i++){    ret=multi_mod(ret,ret,n);    if(ret==n-1)return false;   //满足对所有的i=0,1,2,...,t-1.a^(2^i*x)和-1不同余n的为合数.  // i=0时即使上面循环一开始的那个判定(ret==n-1)  // 所以在素数判定中,这两个条件仅仅作为必要条件而不是充分条件!  }/* if(ret==1)return false; else*/    return true;}bool Miller_Rabin(LL n){  if(n==2)return true;  if(n<2||n%2==0)return false;  LL x=n-1;  LL t=0;  while((x&1)==0){    x>>=1;    t++;  }  //上面的步骤求得n-1=2^k*q,q是奇数.  for(int i=0;i<S;i++){//随机大法,S越大,成功率越大.也可以使用底数组合(2,7,61)。    LL a=rand()%(n-1)+1;  //1-n      if(check(a,n,x,t))return false;//如果是合数,返回false;  }  return true;}LL gcd(LL a,LL b){  if(!b)return a;  else return gcd(b,a%b);}LL Pollard_rho(LL x, LL c){  //函数f(x)=(x^2+c)%n  LL i=1,k=2;  LL x0=rand()%x; // x1为随机数.  LL y=x0;  while(1){    x0=(multi_mod(x0,x0,x)+c)%x;  //x0即x2,y即x1.    LL yx=y-x0;    if(yx<0)yx*=-1;    LL d=gcd(yx,x);// 求gcd的原因是存在更多的因数,而不是只知道p整除n,n=p*q.当求gcd(x,n)>1时则有p,2p,3p,4p...    // 必须abs(y-x0).?    if(d>1&&d<=x)return d;    // if(d==x)return d,即if(y==x0)return x;    if(++i==k)y=x0,k<<=1;//Brents’Algorithm?效率更加?  }}void getpf(LL n){  if(Miller_Rabin(n)){    pfact[ant++]=n;    return ;  }  LL p=n;  while(p>=n){    p=Pollard_rho(p,rand()%(n-1)+1);  }  getpf(p);  getpf(n/p);}int main(){  int T;  LL n;  scanf("%d",&T);  while(T--){    scanf("%lld",&n);    if(Miller_Rabin(n)){      printf("Prime\n");      continue;    }    ant=0;    LL ans;    getpf(n);    ans=pfact[0];    for(int i=1;i<ant;i++)        ans=min(ans,pfact[i]);    printf("%lld\n",ans);  }}



0 0
原创粉丝点击