大素数测试

    技术2022-06-28  50

    关键字 (keywords): 大素数 高效 快速 测试 检测 验证

     

     

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

    基本都是用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)

    /** * @param a: 范围:1<= a <= n-1 * @param n: 为待测试的数(是否是合数) * @param q: m 和 q 满足 n-1 = m*(2^q) * @param m: 同上 * @return 布尔值:n是否是合数 * 时间复杂度:O((log(n))^3) * * ------------------------------------------------- * Miller-Rabin算法 * 算法过程如下: * 先通过其他方法求出:q和m (n-1 = m*(2^q)) * 再x 取(a^m)^1 (a^m)^2 (a^m)^4 (a^m)^8 ...(共q+1个) * 每次取一个后,都要判断: * 如果x^2%n=1 并且x不等于1并且x不等于n-1 * 则n必为合数 * 否则n是素数(既满足Fermat条件,又没有找到证据数) * * 解析以上的话:当x[q]取到(a^m)^2^q时候,即最后一个时候,因为n-1 = m*(2^q) * 故a^(n-1) % n = 1 是满足了Fermat条件,所以大概率是素数 * 如果返回合数,则我们说a是满足n为合数的“证据数” * -------------------------------------------------- */ private static boolean witness1(long a, long n, int q, long m) { long[] x = new long[q + 1]; BigInteger am = BigInteger.valueOf(a); //a的幂 x[0] = am.modPow(BigInteger.valueOf(m), BigInteger.valueOf(n)).longValue(); //long am = (long)Math.pow(a, m); //x[0] = am.longValue() % n; //System.out.println(x[0]); for (int i = 1; i <= q; i++) { BigInteger t = BigInteger.valueOf(x[i - 1]); x[i] = t.multiply(t).mod(BigInteger.valueOf(n)).longValue(); //x[i] = x[i - 1] * x[i - 1] % n; if (x[i] == 1 && x[i - 1] != n - 1 && x[i - 1] != 1) { return true; } } //fermat条件不满足 if (x[q] != 1) return true; //fermat条件满足 return false; } 

     

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

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

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

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

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

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

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

     

     

    改进以后的Miller_Rabin的算法:

     

    private static boolean witness2(long a, long n, int q, long m) { long[] x = new long[q + 1]; //a的幂m long am = (long)Math.pow(a, m); x[0] = am % n; /* * 若a^m%n= 1 * 则a^2m%n = 1, a^4m%n = 1 ... ((a^m)^(2^q))%n = 1 */ if (x[0] == 1) return false;//为素数 for (int i = 1; i <= q; i++) { /* * 如果x % n = n - 1 * 则 x^2 % n = 1, x^4 % n = 1, ... */ if (x[i - 1] == n - 1) return false;//为素数 x[i] = x[i - 1] * x[i - 1] % n; if (x[i] == 1) return true; } return true; } 

     

     

    其他相关代码:

     

    /** * @param from * @param to * @return Integer[] */ public static int[] getRandomDistinctIntegerArray(int from, int to, int num) { int[] ints = new int[num]; HashSet<Integer> sets = new HashSet<Integer>(); java.util.Random r = new java.util.Random(); int cnt = 0; for (int i = 0; i < num; i++) { int ri = from + r.nextInt(to); if (sets.contains(ri)) { i--; continue; } else sets.add(ri); ints[i] = ri; } sets.clear(); return ints; } /** * @param n 必须大于等于 2 * @return */ public static boolean isPrime(int n) { int k; if (n < 100) k = (n / 2); else k = 100; int[] radomInts = Random.getRandomDistinctIntegerArray(1, n - 1, k); int q = 0, m = 0; int t = n - 1; while((int)(t / 2) * 2 == t) { q++; t /= 2; } m = t; // System.out.println("q:" + q + " m:" + m); // System.out.println(Arrays.toString(radomInts)); for (int i = 0; i < k; i++) { //是否是合数 if (witness1(radomInts[i], (long)n, q, m)) { return false;//合数 } } //错判率1/2^k return true;//素数 }  

     

     

    主程序代码:

     

    public static void main(String[] args) { System.out.println(Prime.isPrime(2));//true System.out.println(Prime.isPrime(3));//true System.out.println(Prime.isPrime(4));//false System.out.println(Prime.isPrime(5));//true System.out.println(Prime.isPrime(6));//false System.out.println(Prime.isPrime(7));//true System.out.println(Prime.isPrime(8));//false System.out.println(Prime.isPrime(9));//false System.out.println(Prime.isPrime(10));//false System.out.println(Prime.isPrime(11));//true System.out.println(Prime.isPrime(12));//false System.out.println(Prime.isPrime(13));//true System.out.println(Prime.isPrime(341));//false System.out.println(Prime.isPrime(561));//false System.out.println(Prime.isPrime(645));//false System.out.println(Prime.isPrime(1105));//false System.out.println(Prime.isPrime(1387));//false System.out.println(Prime.isPrime(1729));//false System.out.println(Prime.isPrime(1905));//false System.out.println(Prime.isPrime(100003));//false System.out.println(Prime.isPrime(100019));//false System.out.println(Prime.isPrime(100043));//false System.out.println(Prime.isPrime(100049));//false System.out.println(Prime.isPrime(100057));//false System.out.println(Prime.isPrime(100069));//false for (int i = 0; i < 100000; i++) { System.out.println(Prime.isPrime(1999999999 + i));//false } System.out.println(Prime.isPrime(5)); System.out.println(Prime.isPrime(9973));//true System.out.println(Prime.isPrime(99999989));//true } 

     

     

    本篇博客于2010/01/17前更新,谢谢^_^


    最新回复(0)