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

本文探讨了大素数的测试方法,基于合数的拉宾-米勒测试,介绍了如何判断一个大数是否为素数的必要条件。以POJ1811 Prime Test的实际案例进行说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小黄书第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);
  }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值