大素数“测试”

 

先列出几篇已经写过的大素数测试的文章

基本都是用Miller_Rabin的测试方法

http://blog.csdn.net/fisher_jiang/archive/2006/07/27/986654.aspx

http://www.cppblog.com/zoyi-zhang/archive/2008/09/23/62572.aspx

但似乎都没有实现完整的代码,另外对于Miller_Rabin的方法还有可以改进的地方

 

 

Miller_Rabin的算法:

我们的问题是给定一个数n,想判断它到底是不是素数?

 

首先,根据公式:n - 1 = m * 2q,求出m和q(要求q,只要看n-1的二进制右边有多少个0就是q了)

若太大直接用2除,除到余数不为0为止,这样就可以得到m和q

再根据另外一个公式:(x为1,2,...,n-1中的一个数a的m次方,即am)判断x2%n是不是等于1,

      1. 如果等于1,并且判断x!=1和x!=n-1,就返回合数

      2. 如果不等于1,x=x2,判断x2%n,再到一步骤

如果总共q次循环以后,没有得出是合数,则判断x是不是等于1

如果不等于1,则还是合数

如果等于1,则是素数(满足fermat小定理)


为改进的Miller_Rabin的算法:时间复杂度:O((log(n))3)

[java]  view plain copy
  1. /** 
  2.      * @param a: 范围:1<= a <= n-1  
  3.      * @param n: 为待测试的数(是否是合数)  
  4.      * @param q: m 和 q 满足 n-1 = m*(2^q) 
  5.      * @param m: 同上 
  6.      * @return 布尔值:n是否是合数 
  7.      * 时间复杂度:O((log(n))^3) 
  8.      *  
  9.      * ------------------------------------------------- 
  10.      * Miller-Rabin算法 
  11.      * 算法过程如下: 
  12.      * 先通过其他方法求出:q和m   (n-1 = m*(2^q)) 
  13.      * 再x 取(a^m)^1 (a^m)^2 (a^m)^4 (a^m)^8 ...(共q+1个) 
  14.      * 每次取一个后,都要判断: 
  15.      * 如果x^2%n=1 并且x不等于1并且x不等于n-1 
  16.      * 则n必为合数 
  17.      * 否则n是素数(既满足Fermat条件,又没有找到证据数) 
  18.      *  
  19.      * 解析以上的话:当x[q]取到(a^m)^2^q时候,即最后一个时候,因为n-1 = m*(2^q) 
  20.      *              故a^(n-1) % n = 1 是满足了Fermat条件,所以大概率是素数 
  21.      *              如果返回合数,则我们说a是满足n为合数的“证据数” 
  22.      * -------------------------------------------------- 
  23.      */  
  24.     private static boolean witness1(long a, long n, int q, long m) {  
  25.         long[] x = new long[q + 1];  
  26.         BigInteger am = BigInteger.valueOf(a);  
  27.         //a的幂  
  28.         x[0] = am.modPow(BigInteger.valueOf(m), BigInteger.valueOf(n)).longValue();  
  29.         //long am = (long)Math.pow(a, m);  
  30.           
  31.         //x[0] = am.longValue() % n;  
  32.         //System.out.println(x[0]);  
  33.         for (int i = 1; i <= q; i++) {  
  34.             BigInteger t = BigInteger.valueOf(x[i - 1]);  
  35.             x[i] = t.multiply(t).mod(BigInteger.valueOf(n)).longValue();  
  36.             //x[i] = x[i - 1] * x[i - 1] % n;  
  37.             if (x[i] == 1 && x[i - 1] != n - 1 && x[i - 1] != 1) {  
  38.                 return true;  
  39.             }  
  40.         }  
  41.         //fermat条件不满足  
  42.         if (x[q] != 1return true;  
  43.           
  44.         //fermat条件满足  
  45.         return false;  
  46.     }  

 

 

1. 若am(mod n)=1,则a2m,a4m,…,am*2^q(mod n)均=1(后者是前者平方)

2. 如果对于某个非负整数i有am*2^i(mod n)=n-1,则对于所有

3, 满足i<j≤q的j,均有am*2^j(mod n)=1(实际上,当j>q时也成立)。

(∵(n-1)2=n2-2n+1≡1(mod n))

若n为素数,在首次遇到xm*2^i(mod n)=1(1≤i≤q)之前,

必有am*2^i(mod n)=n-1。(由定理:

若p为素数且0<x<p,则当x2≡1(mod p)时必有x=1或x=p-1。)

 

 


改进以后的Miller_Rabin的算法:

 

[java]  view plain copy
  1. private static boolean witness2(long a, long n, int q, long m) {  
  2.         long[] x = new long[q + 1];  
  3.           
  4.         //a的幂m  
  5.         long am = (long)Math.pow(a, m);  
  6.           
  7.         x[0] = am % n;  
  8.           
  9.         /* 
  10.          * 若a^m%n= 1  
  11.          * 则a^2m%n = 1, a^4m%n = 1 ... ((a^m)^(2^q))%n = 1 
  12.          */  
  13.         if (x[0] == 1)  
  14.             return false;//为素数  
  15.           
  16.           
  17.         for (int i = 1; i <= q; i++) {  
  18.             /* 
  19.              * 如果x % n = n - 1 
  20.              * 则 x^2 % n = 1, x^4 % n = 1, ... 
  21.              */  
  22.             if (x[i - 1] == n - 1)  
  23.                 return false;//为素数  
  24.               
  25.               
  26.             x[i] = x[i - 1] * x[i - 1] % n;  
  27.               
  28.             if (x[i] == 1)  
  29.                 return true;  
  30.         }  
  31.         return true;  
  32.     }  

 

 

 

其他相关代码:

 

[java]  view plain copy
  1. /** 
  2.      * @param from 
  3.      * @param to 
  4.      * @return Integer[] 
  5.      */  
  6.     public static int[] getRandomDistinctIntegerArray(int from, int to, int num) {  
  7.         int[] ints = new int[num];  
  8.         HashSet<Integer> sets = new HashSet<Integer>();  
  9.         java.util.Random r = new java.util.Random();  
  10.         int cnt = 0;  
  11.         for (int i = 0; i < num; i++) {  
  12.             int ri = from + r.nextInt(to);  
  13.             if (sets.contains(ri)) {  
  14.                 i--;  
  15.                 continue;  
  16.             }  
  17.             else  
  18.                 sets.add(ri);  
  19.             ints[i] = ri;  
  20.         }  
  21.         sets.clear();  
  22.         return ints;  
  23.     }  
  24. /** 
  25.      * @param n 必须大于等于  2 
  26.      * @return 
  27.      */  
  28.     public static boolean isPrime(int n) {  
  29.         int k;  
  30.           
  31.         if (n < 100)  
  32.             k = (n / 2);  
  33.         else  
  34.             k = 100;  
  35.         int[] radomInts = Random.getRandomDistinctIntegerArray(1, n - 1, k);  
  36.         int q = 0, m = 0;  
  37.         int t = n - 1;  
  38.           
  39.         while((int)(t / 2) * 2 == t) {  
  40.             q++;  
  41.             t /= 2;  
  42.         }  
  43.         m = t;  
  44. //      System.out.println("q:" + q + " m:" + m);  
  45. //      System.out.println(Arrays.toString(radomInts));  
  46.         for (int i = 0; i < k; i++) {  
  47.               
  48.             //是否是合数  
  49.             if (witness1(radomInts[i], (long)n, q, m)) {  
  50.                 return false;//合数  
  51.             }  
  52.         }  
  53.         //错判率1/2^k  
  54.         return true;//素数  
  55.     }  

 

 

 

主程序代码:

 

[java]  view plain copy
  1. public static void main(String[] args) {  
  2.         System.out.println(Prime.isPrime(2));//true  
  3.         System.out.println(Prime.isPrime(3));//true  
  4.         System.out.println(Prime.isPrime(4));//false  
  5.         System.out.println(Prime.isPrime(5));//true  
  6.         System.out.println(Prime.isPrime(6));//false  
  7.         System.out.println(Prime.isPrime(7));//true  
  8.         System.out.println(Prime.isPrime(8));//false  
  9.         System.out.println(Prime.isPrime(9));//false  
  10.         System.out.println(Prime.isPrime(10));//false  
  11.         System.out.println(Prime.isPrime(11));//true  
  12.         System.out.println(Prime.isPrime(12));//false  
  13.         System.out.println(Prime.isPrime(13));//true  
  14.         System.out.println(Prime.isPrime(341));//false  
  15.         System.out.println(Prime.isPrime(561));//false  
  16.         System.out.println(Prime.isPrime(645));//false  
  17.         System.out.println(Prime.isPrime(1105));//false  
  18.         System.out.println(Prime.isPrime(1387));//false  
  19.         System.out.println(Prime.isPrime(1729));//false  
  20.         System.out.println(Prime.isPrime(1905));//false  
  21.         System.out.println(Prime.isPrime(100003));//false  
  22.         System.out.println(Prime.isPrime(100019));//false  
  23.         System.out.println(Prime.isPrime(100043));//false  
  24.         System.out.println(Prime.isPrime(100049));//false  
  25.         System.out.println(Prime.isPrime(100057));//false  
  26.         System.out.println(Prime.isPrime(100069));//false  
  27.         for (int i = 0; i < 100000; i++) {  
  28.             System.out.println(Prime.isPrime(1999999999 + i));//false  
  29.         }  
  30.         System.out.println(Prime.isPrime(5));   
  31.         System.out.println(Prime.isPrime(9973));//true  
  32.         System.out.println(Prime.isPrime(99999989));//true  
  33.     }  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值