【问题标题】:What is the fastest algorithm for checking if a 14 digit number is prime?检查 14 位数字是否为素数的最快算法是什么?
【发布时间】:2013-05-31 19:28:16
【问题描述】:

我需要最快的程序来检查 14 位(或更大)数字的素数。我在多个网站上进行了搜索,但我不确定我找到的网站是否能处理这么大的数字。

【问题讨论】:

  • Miller Rabin 可以很容易地确定小值(14 位数很小),而且速度非常快。对于非常小的数字,试除法更快。
  • 你需要这个做什么?您需要检查多少个 14 位数字?你能从小范围内挑选它们吗?
  • 使用 (7) 基值对所有值 2^64 形成确定性 Miller-Rabin 测试同样容易。几乎所有候选人都将无法通过 2-SPRP 测试。其他下限不是很好...我的实现(需要 gcc / clang 扩展)是here。另见:miller-rabin.appspot.com

标签: performance testing primes digit


【解决方案1】:

就素数测试而​​言,14 位数字并不是很大。当数字具有某些特殊结构时,可能会提供更快的专用测试(例如,如果它是梅森数),但一般来说,该范围内数字的最快测试是

  1. 按一些小数开始试除。如果您计划进行多次检查,则值得列出n 最小素数,以便试除法仅除以素数,对于单个测试,避免偶数除数(2 除外),以及3(除了3),就足够了。 “小”的含义取决于解释,在 100 和 10000 之间选择截止似乎是合理的,许多(很少)除法仍然很快完成,并且他们找到了绝大多数的合数。

  2. 如果试验除法尚未确定复合数(或素数,如果它实际上小于截止值的平方),您可以使用已知对您的范围具有确定性的快速概率素数测试之一'有兴趣,通常的候选人是

    • Baillie/Pomerance/Selfridge/Wagstaff 检验,一个基于 2 的强 Fermat 检验,然后是一个平方检验和一个(强)Lucas 检验。这在 264 以下不会出现误报,因此对于 14-18 位数字是确定的。
    • 强费马测试已知对所考虑的范围具有确定性的碱基集合。根据Chris Caldwell's prime pages,“如果n < 341,550,071,728,321 是2、3、5、7、11、13 和17-SPRP,那么n 是素数”。

快速确定性通用素数测试、APR-CL、ECPP、AKS 会慢一些,而且实施起来相当困难。他们应该已经在 14 位或更多位数的数字上击败了纯试除法,但比偶然已知的范围概率测试要慢得多。

但是,根据您的用例,最好的方法也可能是筛选一个连续的数字范围(如果您想找到 1014-109 和 1014,例如,一个筛子比几亿个快速的单独素数测试要快得多)。

【讨论】:

    【解决方案2】:

    正如 Daniel Fischer 指出的那样,14 位数字对于素性测试来说并不是特别大。这给了你几个选择。首先是简单的试划分:

    function isPrime(n)
        d := 2
        while d * d <= n
            if n % d == 0
                return Composite
            d := d + 1
        return Prime
    

    10^14 的平方根是 10^7,所以这可能需要一点时间。更快的是使用prime wheel

    struct wheel(delta[0 .. len-1], len, cycle)
    
    w := wheel([1,2,2,4,2,4,2,4,6,2,6], 11, 3)
    
    function isPrime(n, w)
        d := 2; next := 0
        while d * d <= n
            if n % d == 0
                return Composite
            else
                d := d + w.delta[next]
                next := next + 1
                if next == w.len
                    next := w.cycle
        return Prime
    

    这应该可以将幼稚的试用划分速度提高 2 到 3 倍,这可能足以满足您的需求。

    更好的选择可能是 Miller-Rabin 伪素性测试仪。从强伪素测试开始:

    function isStrongPseudoprime(n, a)
        d := n - 1; s := 0
        while d is even
            d := d / 2; s := s + 1
        t := powerMod(a, d, n)
        if t == 1 return ProbablyPrime
        while s > 0
            if t == n - 1
                return ProbablyPrime
            t := (t * t) % n
            s := s - 1
        return DefinitelyComposite
    

    函数返回ProbablyPrime的每个a都是n的素数的见证

    function isPrime(n)
        for a in [2,3,5,7,11,13,17]
            if isStrongPseudoprime(n, a) == DefinitelyComposite
                return DefinitelyComposite
        return ProbablyPrime
    

    正如 Fischer 所说,对于 n paper;如果您想测试较大数字的素数,请选择 25 个见证人a 随机。 powerMod(b,e,m) 函数返回 b ^ e (mod m)。如果您的语言不提供该功能,您可以像这样有效地计算它:

    function powerMod(b, e, m)
        x := 1
        while e > 0
            if e % 2 == 1
                x := (b * x) % m
            b := (b * b) % m
            e := floor(e / 2)
        return x
    

    如果你对这个测试背后的数学感兴趣,我在我的博客上谦虚地推荐这篇文章Programming with Prime Numbers

    【讨论】:

      【解决方案3】:

      循环变量“x”以 1 递增,直到达到数字“num”的值。 循环时使用模数检查 num 是否可被 x 整除。如果余数为 0,则停止。

      例如

      mod = 1;
      while (mod != 0)
      {
      mod = num % x;
      x++;
      }
      

      塔达!质数检查器...不确定是否有比这更快的方法。

      【讨论】:

        【解决方案4】:

        我最近做了一个更快的算法。它可以在几秒钟内轻松地算出一个 14 位数字。只需将此代码粘贴到任何接受 javascript 代码并运行它的地方。请记住,javascript 的版本必须是本文的最新版本,因为它必须支持 BigInteger 才能执行这些操作。通常最新的浏览器(Chrome、firefox、Safari)将支持这样的功能。但任何人都可以猜测其他浏览器(如 Microsoft IE)是否会正确支持它。

        --

        该算法结合了前面提到的一些算法思想。

        不过……

        这个算法实际上是通过可视化素数集并将它们乘以各种不同的值然后对这些值执行各种模运算并使用这些数字创建所有素数的 3d 表示来生成的,从而揭示了存在的真实模式在素数集中。

        var prime_nums = [2n,3n,5n,7n,11n,13n,17n,19n,23n,29n,31n,37n,41n,43n,47n,53n,59n,61n,67n,71n,73n,79n,83n,89n,97n,101n,103n,107n,109n,113n,127n,131n,137n,139n,149n,151n,157n,163n,167n,173n,179n,181n,191n,193n,197n,199n,211n,223n,227n,229n,233n,239n,241n,251n,257n,263n,269n,271n,277n,281n,283n,293n,307n,311n,313n,317n,331n,337n,347n,349n,353n,359n,367n,373n,379n,383n,389n,397n,401n,409n,419n,421n,431n,433n,439n,443n,449n,457n,461n,463n,467n,479n,487n,491n];
        
        function isHugePrime(_num) {
          var num = BigInt(_num);
          var square_nums = [BigInt(9) ,  BigInt(25) , BigInt(49) ,BigInt(77) , BigInt(1) , BigInt(35) , BigInt(55)];
        
          var z = BigInt(30);
          var y = num % z;
        
          var yList = [];
          yList.push(num % BigInt(78));
          var idx_guess = num / 468n;
          var idx_cur = 0;
          while ((z * z) < num) {
              z += BigInt(468);
              var l = prime_nums[prime_nums.length - 1]
        
                 while (l < (z / BigInt(3))) {
                        idx_cur++;
                        l += BigInt(2);
                        if (isHugePrime(l)) {
                            prime_nums.push(l);
                        }
              }
              y = num % z;
              yList.push(y);
        
        
            }
          for (var i=0; i<yList.length; i++) {
              var y2 = yList[i];
              y = y2;
              if (prime_nums.includes(num)) { return true; }
              if ((prime_nums.includes(y)) || (y == BigInt(1)) || (square_nums.includes(y))) {
        
                                  if ((y != BigInt(1)) && ((num % y) != BigInt(0))) {
        
                                     for (var t=0; t<prime_nums.length; t++) {
                                          var r = prime_nums[t];
                                          if ((num % r) == BigInt(0)) { return false; }
                                        }
        
                                      return true;
                                    }
                                  if (y == BigInt(1)) {
                                      var q = BigInt(num);
                                      for (var t=0; t<prime_nums.length; t++) {
                                          var r = prime_nums[t];
                                          if ((q % r) == BigInt(0)) { return false; }
                                        }
        
        
                                      return true;
        
                                    }
        
                               }
        
            }
          return false;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-05-04
          • 2010-10-02
          • 1970-01-01
          • 1970-01-01
          • 2020-09-20
          • 1970-01-01
          • 2011-03-27
          相关资源
          最近更新 更多