poj 1811 Prime Test

// 给出一个大数(unsigned __int64),判断是否素数,若不是素数,则输出最小的素因子
// 素数判断用miller法 分解用pollard法

#include <iostream>
#include <time.h>
#include <cmath>
using namespace std;
unsigned __int64 chen(unsigned __int64 x,unsigned __int64 y,unsigned __int64 n)//计算x*y%n
{
if ((x>>32)==0&&(y>>32)==0) return x*y%n;
unsigned __int64 a1,b1,a2,b2;
a1=(x>>32);
b1=((x<<32)>>32);
a2=(y>>32);
b2=((y<<32)>>32);
unsigned __int64 t1,t2,t3,t4;
t1=b1*b2%n;t2=b1*a2%n;t3=a1*b2%n;t4=a1*a2%n;
int i;
for (i=0;i<32;i++){ t2=(t2<<1)%n;t3=(t3<<1)%n;}
for (i=0;i<64;i++) t4=(t4<<1)%n;
return ((t1+t2)%n+(t3+t4)%n)%n;
}
unsigned __int64 mood(unsigned __int64 a,unsigned __int64 u,unsigned __int64 n) //计算a^u%n
{
unsigned __int64 b,k;
int i;
i=k=0;
while (u>0)
{
i++;
k=(k<<1)+(u&1);
u>>=1;
}
b=1;
while (i-->0)
{
b=chen(b,b,n);
if (k&1) b=chen(b,a,n);
k>>=1;
}
return b;
}
unsigned __int64 witness(unsigned __int64 a, unsigned __int64 n)//计算a^(n-1)%n 其中如果遇到1的非平凡平方根 就直接返回合数
{
unsigned __int64 i,x,y,t,u;
u=n-1;t=0;
while ((u&1)==0)
{
u>>=1;
t++;
}
x=mood(a,u,n);
for (i=0;i<t;i++)
{
y=chen(x,x,n);
if (y==1&&x!=1&&x!=n-1)
return x;
x=y;
}
return x;
}
unsigned __int64 miller(unsigned __int64 n)//miller部分 多测几次
{
int i;
unsigned __int64 j;

if (n==2) return 1 ;
for (i=0;i<50;i++)
{
j=rand()%(n-2)+1;
unsigned __int64 k=witness(j,n);
if (k!=1)
{
return k;
}
}
return 1;
}
unsigned __int64 gcd(unsigned __int64 a,unsigned __int64 b) //最大公约数
{
unsigned __int64 c;
if (a<b){c=a;a=b;b=c;}
while (b!=0)
{
c=a;a=b;b=c%b;
}
return a;
}
unsigned __int64 pollard(unsigned __int64 n,unsigned __int64 x)//pollard tot用于卡时防止死掉
{
unsigned __int64 i,k,y,d;
unsigned __int64 tot=1<<20;
i=1;y=x;k=2;
while (1)
{
i++;
tot--;
x=(chen(x,x,n)-1+n)%n;
d=gcd((y-x+n)%n,n);
if (d!=1&&d!=n) return d;
if (i==k)
{
y=x;
k=(k<<1);
}
if (tot==0) return 1;

}
}
int main()
{
unsigned __int64 n,m;
int cass;
srand(time(0));
for (cin>>cass;cass>0;cass--)

{
scanf("%I64d",&n);

if (n==2)
goto isprim;
if ((n&1)==0)
{
cout<<2<<endl;
continue;
}

if (miller(n)==1)
{
isprim: cout<<"Prime"<<endl;
continue;
}
unsigned __int64 d=pollard(n,2);
n/=d;
unsigned __int64 mind=d;
if (mind==1) mind=99999999999999;
while (miller(n)!=1)
{
m=rand()%(n-1)+1;
d=pollard(n,m);
if (d>1&&mind>d) mind=d;
n/=d;
}
if (mind>n) mind=n;
printf("%I64d\n",mind);
}
return 0;
}

posted on 2012-03-22 01:25  sysu_mjc  阅读(169)  评论(0编辑  收藏  举报

导航