bool test (LL n,LL a,LL d)
{
if(n==2)
return true;
if(n==a)
return true;
if((n&1)==0)
return false;
while(!(d&1))
d=d>>1;
LL t=pow_mod(a,d,n);
while((d!=n-1)&&(t!=1)&&(t!=n-1))
{
t=(LL)t*t%n;
d=d<<1;
}
return (t==n-1||(d&1)==1);
}
bool isPrime(LL n)
{
if(n<2)
return false;
LL a[]= {2,3,5,7,61};
for(int i=0; i<=4; i++)
if(!test(n,a[i],n-1))
return false;
return true;
}
int p[10005],a[10005];
void prime()
{
int i,n=10005,t=1,j;
a[1]=0;
for(i=2;i<=n;i++)
a[i]=1;
for(i=2;i<=n;i++)
if(a[i])
{
p[t++]=i;
for(j=i;j<=n;j+=i)
a[j]=0;
}
}
//t要从1开始 从0开始第一个2会变成0 好奇怪。。。
int prime(int n)
{
int i,q;
q=(int)sqrt(n);
for(i=0;p[i]<=q;i++)
if(n%p[i]==0)return 0;
return 1;
}
int p[8]={4,2,4,2,4,6,2,6};
int prime(int n)
{
int i=7,j,q;
if(n==1)return 0;
if(n==2||n==5||n==3)return 1;
if(n%2==0||n%3==0||n%5==0)return 0;
q=(int)sqrt(n);
for(;i<=q;){
for(j=0;j<8;j++){
if(n%i==0)return 0;
i+=p[j];
}
if(n%i==0)return 0;
}
return 1;
}
米勒罗宾算法的核心是课上提到的费马小定理:
即如果一个数n 它的 a^(n-1)%n !=1 (0
如果 a^(n-1)%n ==1 (0)
1 随机取一个 a
2 如果 它不满足 a^(n-1)%n ==1
3 则它一定是 合数
4 退出
5 如果它满足 a^(n-1)%n ==1
6 则它是一个素数的概率是1/2
7 回到 1
如果对这个过程重复50次,每次都没说它是合数,那这个数是素数的概率是多少那?
它只有(1/2)^50可能不是素数!
很显然就像是投硬币那样如果你投了1000次,每次都投到正面 ,那你就会怀疑这个硬币2面都是正面!
米勒罗宾算法的算法很简单,但是由于需要计算a^(n-1)%n这类的问题,如果不经行优化,对于大数计算时间复杂度仍旧很高。
下面Witness(long a,long n)这个函数就是用java实现的a^(n-1)%n的比较快速的大数计算。
Witness计算的核心是"模运算"
把a 分解成 t个2 和 奇数u的乘积 ,比如 144 可以分解成4个2 和一个9的乘积
于是根据"模运算",我们可以把计算a^(n-1)%n,分解成计算 4次(a^2)迭代计算和a^9%n的计算
对于4次(a^2)迭代计算,只需一个for,执行 t次
对于a^9%n的计算可参考Modular_Exponentiation(long a, long b,long n)实现
具体方法为
定义一个数d为结果,初始值为1
将9化为2进制1001(2^0方位是第一位)共四位
则做四次操作
d=d*d%n
如果当前位为1则再做
d=d*a%n