最近在看RSA,找到一个一个大素数是好多加密算法的关键一步,而大素数无法直接构造,一般情况下都是生成一个随机数然后判断是不是素数。判断是否是素数的方法有好多,有的能够准确判断,比如可以直接因式分解(RSA的安全性就基于这是困难的),速度稍微快一点的对素数又有特殊要求,而Miller-Rabin素数检测法可以在一定概率上认为一个数是素数,以极小概率的错误换取时间。Miller-Rabin算法基于一个数如果是素数就满足费马小定理,即a^(n-1) ≡1(mod n),而如果满足此现象却不是素数就成为基于a的伪素数(Carmichael)数,Carmichael数是非常少的。在1~100000000范围内的整数中,只有255个Carmichael数。Miller-Rabin使用多个随机生成的a进行检测就可以将错误率降低到相当低,并且在每次计算模取幂时如果发现对模n来说1的非平凡平方根,就可以提前判断n为素数了。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <math.h>
 4 
 5 #define S 50
 6 
 7 int miller_rabin(int n,int s);
 8 bool witness(long long base,long long n);
 9 
10 int main()
11 {
12     int m;
13     while(scanf("%d",&m) != EOF){
14         int n,cnt = 0;
15 
16         for(int i = 0;i < m;i++){
17             scanf("%d",&n);
18 
19             if(n % 2 == 0){
20                 cnt += (n == 2);
21             }
22             else{
23                 cnt += miller_rabin(n,S);
24             }
25         }
26 
27         printf("%d\n",cnt);
28     }
29 
30     return 0;
31 }
32 
33 int miller_rabin(int n,int s)
34 {
35     for(int i = 0;i < s && i < n;i++){
36         long long base = rand() % (n - 1) + 1;
37 
38         if(witness(base,n)){
39             return 0;    
40         }
41     }
42 
43     return 1;
44 }
45 
46 bool witness(long long base,long long n)
47 {
48     int len = ceil(log(n - 1.0) / log(2.0)) - 1; 
49     long long x0 = 0,x1 = 1;
50 
51     for(int i = len;i >= 0;i--){
52         x0 = x1;
53         x1 = (x1 * x1) % n;
54 
55         if(x1 == 1 && x0 != 1 && x0 != n - 1){
56             return true;
57         }
58         if(((n - 1) & (1 << i)) > 0){
59             x1 = (x1 * base) % n;
60         }
61     }
62     return x1 != 1;
63 }
64 
65 //10902607    2014-06-23 23:34:23    Accepted    2138    125MS    228K    946 B    G++    超级旅行者

 


 

 posted on 2014-06-23 23:55  莫扎特的代码  阅读(174)  评论(0编辑  收藏  举报