素性测试,用Miller-Rabin算法,今天才知道我之前米勒罗宾算法学的不对...刚纠正过来,顺便学了一个O(logn)的快速乘法,与O(logn)的快速幂原理一样,把一个数拆分成二进制,然后按位做乘法,在数特大的时候可以避免爆long long,另外还有一个做法是利用类型转换,long long 转double,进行运算,这个我就不太了解了(对double类型不感冒)
这是较好的Miller-Rabin学习资料http://www.matrix67.com/blog/archives/234,神Matrix67写的。
然后这张图是群里别人给的,根据这个选择底数个数,确保算法正确性。
下面是代码,用第一种二进制思想的快速乘法时间是500+ms,第二种类型转换思想实现的代码时间是46ms...
//Miller-Rabin素性测试
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxp 9
typedef long long llong;
int P[maxp]={2,3,5,7,11,13,17,19,23};
/*llong quickmul(llong a,llong b,llong n)
{
llong ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%n;
a=(a*2)%n;
b>>=1;
}
return ans;
}*/
llong quickmul(llong a,llong b,llong n)
{
llong c=(llong)((double)a*(double)b/(double)n);
return (a*b+n-c*n)%n;
}
llong quickpow(llong a,llong b,llong n)
{
llong ans=1;
while(b)
{
if(b&1)
// ans=(ans*a)%n;
ans=quickmul(ans,a,n);
// a=(a*a)%n;
a=quickmul(a,a,n);
b>>=1;
}
return ans;
}
bool Miller_Rabin(llong x)
{
if(x==2)
return true;
if(x==1||x%2==0)
return false;
bool ans=true;
llong d=x-1,t,p;
int i;
while(!(d&1))
d>>=1;
for(i=0;i<maxp&&P[i]<x;++i)
{
t=d;
p=quickpow(P[i],t,x);
while(t!=x-1&&p!=1&&p!=x-1)
{
// p=(p*p)%x;
p=quickmul(p,p,x);
t<<=1;
}
ans&=((p==x-1)||(t&1==1));
if(ans==false)
return ans;
}
return ans;
}
int main()
{
llong x;
while(scanf("%I64d",&x)!=EOF)
if(Miller_Rabin(x))
cout<<"It is a prime number."<<endl;
else
cout<<"It is not a prime number."<<endl;
return 0;
}
ps:调试代码发现个细节,位操作符的优先级很低,甚至比输入输出操作符都低,注意加括号,之前写成d&1==0,wa了好多次。