#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; #define maxn 100005 #define mod 9901 int prime[maxn]; bool unprime[maxn]; void getprime() { int i,j,k = 0; for(i = 2; i <maxn; i++) { if(!unprime[i]) { prime[k++] = i; } for(j = 0; j < k && prime[j]*i <maxn; j++) { unprime[prime[j] *i] = true; if(i % prime[j] == 0) { break; } } } } int main() { getprime(); for(int i=0;i<30;i++) printf("%d ",prime[i]); return 0; } --------------------------------------------------------------------------------------------------------------------------------------------- 于是进入我们今天的主题,Miller_rabin算法,优势可以单独判断一个大数是否素数。缺点他是一个不保证正确的算法,我们只能通过多次执行算法让这个错误的概率很小,不过幸运的是通常来看它的错误概率可以小到忽略不计。 Miller_rabin算法描述 算法的理论基础: 1. Fermat定理:若n是奇素数,a是任意正整数(1≤ a≤ n−1),则 a^(n-1) ≡ 1 mod n。 2. 推演自Fermat定理(具体过程我没看懂,Orz), 如果n是一个奇素数,将n−1表示成(2^s)*d的形式,d是奇数,a与n是互素的任何随机整数,那么a^d ≡ 1 mod n或者对某个r (0 ≤ r≤ s−1, j∈Z) 等式a^((2^r)*d) ≡ −1 mod n 成立。 聪明的读者已经发现上述的定理是一个数是素数的必要条件而非充分条件,所以这就是这个算法的不精确的原有,对于一些特定的检验算子a,存在一些合数也满足上述定理。所以我们要多找几个a反复检验,这样能让错误率大大降低。 那么我们按照上述的定理2,首先重复n次实验。对于每一次实验,随机取检验算子a,带入定理2进行检验,看看在算子a下,n能否满足 a^d ≡ 1 mod n或者对某个r(0 ≤ r≤ s−1, j∈Z) 等式a^((2^r)*d) ≡ −1 mod n ** 如果任意一次实验不满足,则判定不是素数,如果都满足,可近似可以认为是素数(错误率极小)。 代码实现如下:(代码中的q_mul和q_pow表示快速乘法和快速幂运算,具体讲解请参考另一篇博文) #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <map> using namespace std; const int times = 20; int number = 0; map<long long, int>m; long long Random( long long n ) //生成[ 0 , n ]的随机数 { return ((double)rand( ) / RAND_MAX*n + 0.5); } long long q_mul( long long a, long long b, long long mod ) //快速计算 (a*b) % mod { long long ans = 0; while(b) { if(b & 1) { ans =(ans+ a)%mod; } b >>=1; a = (a + a) % mod; } return ans; } long long q_pow( long long a, long long b, long long mod ) //快速计算 (a^b) % mod { long long ans = 1; while(b) { if(b & 1) { ans = q_mul( ans, a, mod ); } b >>= 1; a = q_mul( a, a, mod ); } return ans; } bool witness( long long a, long long n )//miller_rabin算法的精华 {//用检验算子a来检验n是不是素数 long long d= n - 1;//n=(2^s)*d-1; int s= 0; while(d % 2 == 0) { d /= 2; s++; } long long x = q_pow( a, d, n ); //得到a^d mod n if(x == 1 || x == n - 1) return true; //余数为1则为素数 while(s--) //否则试验条件2看是否有满足的 s { x = q_mul( x, x, n ); if(x == n - 1) return true; } return false; } bool miller_rabin( long long n ) //检验n是否是素数 { if(n == 2) return true; if(n < 2 || n % 2 == 0) return false; //如果是2则是素数,如果<2或者是>2的偶数则不是素数 for(int i = 1; i <= times; i++) //做times次随机检验 { long long a = Random( n - 2 ) + 1; //得到随机检验算子 a if(!witness( a, n )) //用a检验n是否是素数 return false; } return true; } int main( ) { long long tar; while(cin >> tar) { if(miller_rabin( tar )) //检验tar是不是素数 cout << "Yes, Prime!" << endl; else cout << "No, not prime.." << endl; } return 0; } 嗯,就是这样,至于那个定理我真的不是很清楚为何为这样,有一篇讲解文你们有兴趣的话看看吧。
http://blog.csdn.net/fisher_jiang/article/details/986654
