计算一个尽可能大的素数

在有限的时间内,计算出一个尽可能大的素数

一.问题点

  • 有限时间:在一个可接受的时间范围内,并非依靠暴力求解
  • 尽可能大:可计算素数的上限
  • 素数:因数只有1和它本身的自然数

二.素数的生成

n 位的十进制位的大素数生成步骤如下:

  1. 产生一个 n 位的随机数p
  2. 若最低位为偶数, 则将它加1, 以确保该素数为奇数, 从而保证了平均节省一半的运算时间
  3. 检查以确保 p 不能被任何小素数整除, 如 3, 5, 7, 11 等等,目的是排除 p 是合数的绝大部分可能性, 减少了下面步骤对 p 进行素数测试的总次数, 从而大大节省了运算时间。我采用了除2 以外(因已经检验过 p 的奇偶性)的所有小于 20 的素数, 来测试 p 对于它们的整除性
  4. 产生一个随机数 a, 对 a 进行 Rabin- Miller测试,如果 p 通过测试, 则另外产生一个随 机数 a, 再重新进行测试选取较小的 a 值,以保证较快的运算速度,作 3次Rabin-Miller 测试(1次看起来已足够, 但为保证较高的精确性, 可以多做几次)
  5. 如果 p 通过测试, 则 p 是素数,否则将原被测试数加 2, 得到一个新的数, 再对新数进行测试, 直到找到一个素数为止

三.Miller-Rabin 算法

Miller-Rabin 算法是一种基于概率的素性测试算法,因此该算法与一般的基于事实的真素性测试方法的区别是:存在一定的误判率。但是在对于某个较大的待测数字进行多次测试的情况下,误判率可以控制在可忽略范围内。Miller-Rabin算法基于 Fermat 算法,属于后者的变形、改进。

首先引入 Fermat定理:n是一个奇素数,a是任何整数(1 ≤ a ≤ n-1) ,则a^(n-1)≡1(mod n)根据此定理可以知道,对于给定的待测数字 n,可以通过设定素性测试算法,计算 w = a^(n-1)%n的结果来判定。

  • W!=1,n一定不是素数;

  • W==1,n可能是素数;

再引入二次探测定理,如果 n 是一个整数,且 0<x<n,则:x2%p=1 有: x= 1 / x = p-1。若n是素数,则( n-1 )一定是偶数,因此可令(n-1)=m*(2^q),其中m是正奇数( 若n是偶数,则上面的m*(2^q)一定可以分解成一个正奇数乘以2的k次方的形式 ),q是非负整数。

借助 Fermat 定理,进行如下测试:a^(m)%n、a^(2m)%n、a^(4m)%n、a^(m*(2^q))%n。进行这些测试的过程为:Miller-Rabin 测试。

误判率:若 n 是素数,a 是小于 n 的正整数,则 n 对以 a 为基的Miller 测试,结果为真。Miller 测试进行 k次,将合数当成素数处理的错误概率最多不会超过 4^(-k)。

四.Java程序实现

/**
 * 题目8:计算一个尽可能大的素数
 * 题目描述:在有限的时间内,计算出一个尽可能大的素数。
 */
package edu.sust;

import java.util.Random;
import java.util.Scanner;

public class PrimeNumber {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();    //开始时间
        Scanner scanner = new Scanner(System.in);
        long executeTime;//程序执行时间
        System.out.println("请输入程序运行的时间(毫秒为单位):");
        executeTime = scanner.nextLong();
        long endTime = System.currentTimeMillis();  //结束时间
        int maxPrime = 2;   //最大素数
        while (endTime - startTime < executeTime) {
            int num = getRandom();
            if (num > maxPrime) {
                if (MillerRabin(num, 3))
                    maxPrime = num;
            }
            endTime = System.currentTimeMillis();
        }
        System.out.println(maxPrime);
        scanner.close();
    }

    public static int getRandom() {
        Random random = new Random();
        int num = random.nextInt(Integer.MAX_VALUE);
        if ((num & 1) != 1) {
            num++;//若最低位为偶数, 则将它加1, 以确保该素数为奇数
        }
        //检查以确保 p 不能被任何小素数整除
        int[] primes = {3, 5, 7, 11, 13, 17, 19};
        for (int i = 0; i < primes.length; i++) {
            if (num % primes[i] == 0)
                return -1;
        }
        return num;
    }

    /**
     * 利用费马小定理求大数幂取模
     *
     * @param a 底数
     * @param b 指数
     * @param n 模数
     * @return 返回(a ^ b) mod n的值
     */

    public static int FermatPower(int a, int b, int n) {
        int result = 1;
        while (b > 0) {
            if ((b & 1) == 1)
                result = (result * a) % n;
            if ((a * a) % n == 1 && a != 1 && a != n - 1)
                return -1;// 二次探测
            b >>= 1;
            a = (a * a) % n;
        }
        return result;
    }

    /**
     * Miller-Rabin素性测试
     *
     * @param n    待测随机数
     * @param time 检测次数
     * @return 若通过测试,返回true,否则返回false
     */
    public static boolean MillerRabin(int n, int time) {

        Random random = new Random();

        for (int i = 0; i < time; i++) {
            if (FermatPower(random.nextInt(n - 1) + 2, n - 1, n) != 1)
                return false;
        }
        return true;
    }
}

参考文献

  1. 刘少涛, 凌捷. 数据加密算法与大素数的生成及运算[J]. 广东工业大学学报, 2001(04):27-31.
  2. 张宏, 刘晓霞, 张若岩. RSA公钥密码体制中安全大素数的生成[J]. 计算机技术与发展, 2008(09):137-139+143.
  3. 韩了了, 傅兴华, 刘新华, et al. 一种基于RSA公钥密码体制大素数的生成方法[J]. 贵州大学学报(自然科学版), 2005(04):101-104.
发布了395 篇原创文章 · 获赞 130 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_40507857/article/details/103778071