更严格的界限:
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);
}
这些估算不应该低于实际的第n个质数,适用于任何64位输入,比Robin之前给出的公式(或Wimblik的复杂范围限制公式)更接近一个数量级或更多。对于我的用途,我有一个稍大一些的小质数表,因此可以更加紧密地缩小最后的估计。从公式上讲,我们可以使用floor()而不是ceil(),但我担心精度问题。
编辑:另一种改进方法是实现良好的素数计数界限(例如Axler 2014),并在它们上进行二分查找。 我的代码使用这种方法要比上面的方式慢大约10倍(仍然在1毫秒内运行),但可以将误差百分比降低一个数量级。
如果您想要第n个质数的估计值,可以进行以下操作:
最后,如果您拥有非常快的素数计数方法,例如LMO实现之一(现在有三个开源实现),则可以编写快速精确的第n个质数方法。 计算第10^10个质数只需几毫秒,而计算第10^13个质数只需几秒钟(在现代快速计算机上)。 所有大小的近似值都非常快速,并且适用于更大的数字,但每个人对“大”有不同的想法。
flogn = log(flogn);
可能应该是 flog2n = log(flogn);
。 - President James K. Polk感谢所有的回答,我本来就觉得应该有一个相当简单的方法,但那时候我找不到。我也做了更多的研究。
由于我想用它来生成前n个质数的筛子,我希望这个近似值大于或等于第n个质数。(因此,我要求第n个质数的上界。)
维基百科给出了n >= 6
时的上界。
p_n <= n log n + n log log n (1)
其中p_n
是第n个质数,log
表示自然对数。这是一个不错的起点,但它可能会高估很多。 这篇文章在《大学数学杂志》中为n >= 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 >= 7022
时使用第二种近似方法,当 6 <= n < 7022
时使用第一种近似方法,并对前5个质数进行数组查找。
尽管第一种方法在我使用它的范围内并不是一个非常紧密的界限,但我并不担心,因为我想用这个筛子来筛选较小的数字,而筛选较小的数字是计算便宜的。
p_8597
= 88789,但是该公式给出的结果是88759.3,比实际值低。看起来当 n >= 8602 时这个公式可能没问题。 - Charphacyp_8621 = 89009, p ∈ [88746.2, 89014.4], delta ∈ [-0.9718, -0.9407]
。通过选择8621,您可以使用常量-0.9407获得略微更好的近似值。下一个改进在p_15957
处。是的,这篇论文一定是错的。 - starblueP(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;
我的最佳质数(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))))))
这是我最近更为实验性的公式。
顺便说一下,第十万亿个质数是 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)))))))