【问题标题】:Is there a way to find the approximate value of the nth prime?有没有办法找到第 n 个素数的近似值?
【发布时间】:2010-11-05 18:37:45
【问题描述】:

是否有一个函数可以返回第 n 个素数的近似值?我认为这类似于近似的反素数计数函数。例如,如果我给这个函数 25 它会返回一个大约 100 的数字,或者如果我给这个函数 1000 它会返回一个大约 8000 的数字。我不在乎返回的数字是否是素数,但我确实想要它要快(所以不会生成第一个 n 个素数来返回第 n 个。)

我想要这样,以便我可以使用筛子(EratosthenesAtkin)生成前 n 个素数。因此,理想情况下,第 n 个素数的近似值永远不会低估实际第 n 个素数的值。

(更新:请参阅my answer,了解找到第 n 个素数上限的好方法。)

【问题讨论】:

标签: math primes sieve


【解决方案1】:

Prime number theorem 给出了低于阈值的素数数量,因此它可用于给出第 n 个素数的近似值。

【讨论】:

    【解决方案2】:

    作为粗略估计,您可以使用 n*ln(n) 作为第 n 个素数的近似值。还有一种更复杂但更准确的方法,您可以在 Wikipedia here 上找到详细信息。

    【讨论】:

      【解决方案3】:

      使用筛子可能无法实现有效的实施。想想如果你想拥有前 10.000 个素数会发生什么。您可能需要对大量数字进行筛选。

      您自己在this questionmy answer 中的实现是在不了解应用程序的情况下实现此功能的好方法。素数的值

      【讨论】:

        【解决方案4】:

        感谢所有这些答案。我怀疑有这样相当简单的东西,但当时我找不到。我也做了更多的研究。

        因为我希望 sieve 生成第一个 n 个素数,所以我希望近似值大于或等于第 n 个素数。 (因此,我想要第 n 个素数的上限。)

        Wikipedia 给出n >= 6 的以下上限

        p_n <= n log n + n log log n   (1)
        

        p_n 是第 n 个素数,log 是自然对数。这是一个好的开始,但它可能会高估一个不可忽视的数量。 This article in The College Mathematics Journaln &gt;= 7022 提供了更严格的上限

        p_n <= n log n + n (log log n - 0.9385)   (2)
        

        这是一个更严格的界限,如下表所示

        n         p_n         approx 1    error%  approx 2    error%
        1         2                            
        10        29          31          6.90 
        100       541         613         13.31
        1000      7919        8840        11.63
        10000     104729      114306      9.14    104921      0.18
        100000    1299709     1395639     7.38    1301789     0.16
        1000000   15485863    16441302    6.17    15502802    0.11
        10000000  179424673   188980382   5.33    179595382   0.10
        

        我实现了我的第 n 个素数逼近函数,以使用 n &gt;= 7022 的第二个逼近、6 &lt;= n &lt; 7022 的第一个逼近以及前 5 个素数的数组查找。

        (虽然第一种方法的界限不是很紧,尤其是在我使用它的范围内,但我并不担心,因为我想要这个作为筛子,而且数字较小的筛子在计算上很便宜。)

        【讨论】:

        • 不幸的是,这个公式似乎被打破了。 p_8597 = 88789,但公式给出了 88759.3,这是一个低估。看起来 n >= 8602 可能没问题。
        • 从检查素数到 2e9 我得到:p_8621 = 89009, p ∈ [88746.2, 89014.4], delta ∈ [-0.9718, -0.9407] 通过选择 8621,您可以使用常数 -0.9407 获得更好的近似值。下一个改进是p_15957。是的,论文一定是错的。
        • 根据 Dussart 的说法,从n > 39017 开始,界限实际上成立:“对于 k≥2,第 k 个素数大于 k(lnk+lnlnk−1)。”,数学。比较,68(225),411--415。
        • @DavidJohnstone :文章链接似乎已损坏。能否提供一个更新的链接?
        • @Gaurav,这是论文的当前工作链接,An Upper Bound on the Nth Prime: maa.org/sites/default/files/jaroma03200545640.pdf
        【解决方案5】:

        我的最佳 Prime(n) 估计

        1/2*(8-8.7*n-n^2+
        1/2*(2*abs(log(n)/log(3)+log(log(n)/log(2))/log(2))+
        abs((log(log(3))-log(log(n))+2*n*log(log(n)/log(2))+
        sqrt(((8*log(3)*log(n))/log(2)-log(log(2))+
        log(log(n)))*log(log(n)/log(2))))/log(log(n)/log(2))))*(-1+
        abs(log(n)/log(3)+log(log(n)/log(2))/log(2))+abs(-(1/2)+n+
        sqrt(((8*log(3)*log(n))/log(2)-log(log(2))+
        log(log(n)))*log(log(n)/log(2)))/(2*log(log(n)/log(2))))))
        

        这是我最近的更多实验公式。 顺便提一句。第 10 万亿个素数是323,780,508,946,331 这个公式在这个规模上运行得很好,不确定它是否继续比n*ln(n)+n*(ln(ln(n))-0.9385) 更接近。

        1/2*(3-(8+ln(2.3))*n-n^2+1/2*(-1+
        abs(-(1/2)+n+sqrt(ln(ln(n)/ln(2))*(-ln(ln(2))+ln(ln(n))+
        (8*ln(3)*ln((n*ln(8*n))/ln(n)))/ln(2)))/(2*ln(ln((n*ln(8*n))/
        ln(n))/ln(2))))+abs(ln(n)/ln(3)+ln(ln((n*ln(8*n))/ln(n))/ln(2))/
        ln(2)))*(2*abs(ln((n*ln(8*n))/ln(n))/ln(3)+ln(ln((n*ln(8*n))/ln(n))/
        ln(2))/ln(2))+abs(1/ln(ln(n)/ln(2))*(ln(ln(3))-ln(ln(n))+2*n*ln(ln(n)/
        ln(2))+sqrt(((8*ln(3)*ln(n))/ln(2)-ln(ln(2))+ln(ln((n*ln(8*n))/ln(n))))*
        ln(ln((n*ln(8*n))/ln(n))/ln(2)))))))
        

        【讨论】:

        • 这些都不起作用。我给它 1000,得到一个负数。
        【解决方案6】:

        更严格的界限:

        static const unsigned short primes_small[] = {0,2,3,5,7,11};
        
        static unsigned long nth_prime_upper(unsigned long n) {
          double fn = (double) n;
          double flogn, flog2n, upper;
          if (n < 6)  return primes_small[n];
          flogn  = log(n);
          flog2n = log(flogn);
        
          if      (n >= 688383)    /* Dusart 2010 page 2 */
            upper = fn * (flogn + flog2n - 1.0 + ((flog2n-2.00)/flogn));
          else if (n >= 178974)    /* Dusart 2010 page 7 */
            upper = fn * (flogn + flog2n - 1.0 + ((flog2n-1.95)/flogn));
          else if (n >=  39017)    /* Dusart 1999 page 14 */
            upper = fn * (flogn + flog2n - 0.9484);
          else                    /* Modified from Robin 1983 for 6-39016 _only_ */
            upper = fn * ( flogn  +  0.6000 * flog2n );
        
          if (upper >= (double) ULONG_MAX) {
             /* Adjust this as needed for your type and exception method */
            if (n <= 425656284035217743UL) return 18446744073709551557UL;
            fprintf(stderr, "nth_prime_upper overflow\n"; exit(-1);
          }
        
          return (unsigned long) ceil(upper);
        }
        

        这些不应小于实际的 nth_prime,应该适用于任何 64 位输入,并且比 Robin 早先给出的公式(或 Wimblik 的复杂范围限制公式)一个数量级或更接近。对于我的使用,我有一个稍大的小素数表,因此可以进一步加强最后的估计。从技术上讲,我们可以使用 floor() 而不是 ceil() 的公式,但我担心精度。

        编辑:改进这一点的另一个选择是实现良好的素数边界(例如 Axler 2014)并对它们进行二进制搜索。我的这个方法的代码比上面的要长约 10 倍(仍然运行在一毫秒内),但可以将错误百分比降低一个数量级。

        如果你想估计第 n 个素数,你可以这样做:

        • Cipolla 1902(参见第 12 页 Dusart 1999this paper。我发现三个项 (m=2) 加上一个三阶校正因子很有用,但如果项越多,它就会振荡太多。公式中显示维基百科链接就是这个公式(m=2)。使用下面的两项逆 li 或逆黎曼 R 会得到更好的结果。
        • 计算 Dusart 2010 上限和下限并对结果进行平均。还不错,但我怀疑使用加权平均值会更好,因为边界不是同样严格。
        • li^{-1}(n) 由于 li(n) 是素数的一个不错的近似值,因此倒数是一个不错的 nth_prime 近似值。这和其他所有操作都可以作为函数的二分搜索相当快地完成。
        • li^{-1}(n) + li^{-1}(sqrt(n))/4 更接近,因为它越来越接近 R(n)
        • R^{-1} 逆黎曼 R 函数是我所知道的最接近的平均近似值。

        最后,如果您有一个非常快速的素数计数方法,例如 LMO 实现之一(现在有三个开源实现),您可以编写一个快速精确的 nth_prime 方法。计算第 10^10 个素数可以在几毫秒内完成,第 10^13 个素数可以在几秒钟内完成(在现代快速机器上)。近似值在所有大小下都非常快,并且适用于更大的数字,但每个人对“大”的含义有不同的理解。

        【讨论】:

        • 这是最好的答案,但我认为其中有一点小错误。声明flogn = log(flogn); 应该是flog2n = log(flogn);
        • @GregS,谢谢!固定的。我还添加了一段关于使用反素数限制的内容。
        • @DanaJ 这是我读过的关于素数的最佳作品,我认为素数会让我着迷。有没有机会以牺牲精度为代价使用prime number theorem
        • @DarshanPatil 甚至比不上estimates by Christian Axler,这是当今该主题的最佳作品。
        • @vitaly-t 是的,我同意 谢谢你让我know!? ✌️
        【解决方案7】:

        为了补充 Dana J 的上限,这个公式应该给你一个很好的下限。

        P(n) = (((2 Log(3, n + 2))/(Log(2.5, 2) + Log(3, 3)) + (2 Log(3, n - 2))/(Log(3, 2) + Log(3, 3)))/2) n;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-03-13
          • 2021-02-09
          • 2015-04-04
          • 2013-01-22
          • 2015-04-22
          • 1970-01-01
          • 2016-02-01
          • 1970-01-01
          相关资源
          最近更新 更多