计算素数列表中数字位置的最佳方法是什么?

时间:2012-09-30 00:17:34

标签: python math

例如

f(2)->1
f(3)->2
f(4)->-1 //4 is not a prime
f(5)->3
...

通常,在达到x

之前制作一个素数发生器并计数
def f(x):
    p = primeGenerator()
    count=1
    while True:
        y = next(p)
        if y>x:
            return -1
        elif y==x:
            return count
        else:
            count+=1

是不是太慢了?虽然我可以缓存下一个调用的列表,如果我保证输入必须是素数,所以不必测试输入数是否为素数,是否有更快的公式得到答案?

2 个答案:

答案 0 :(得分:3)

最好的方法取决于您获得的输入,以及该函数是多次调用还是仅调用一次或几次。

如果经常调用它,并且你要接收的所有输入都很小,不大于10 7 ,那么最好的方法是提前创建一个查找表,然后看看输入。

如果不经常调用,并且所有输入都很小,只需生成不超过输入的素数并计算它们当然就足够了。它可能是一个增强功能,可以记住你下次调用已有的内容,这样当第一个参数是19394489,下一个是20889937时,你不需要再次从0开始,但只需要找到它们之间的素数。他们。但额外的存储是否值得拥有取决于传递的参数。

如果它经常被调用并且参数不是太大,不超过10 13 ,那么最好的方法是为π(n)的某些选择值预先计算n的值{1}},并为每个参数查找下一个较小的预计算点的值,然后生成并计算该点与目标值之间的素数(或者如果目标更接近下一个更大的预计算点,则计算目标和那之间的素数。

如果您计算,例如对于10 7 的所有倍数π(n),不超过10 13 ,你得到一个包含一百万个条目的查找表,这对现在的内存并不是很费力,并且永远不需要筛选超过500万的范围,这不需要很长时间。

您还可以将查找表作为磁盘上的文件或数据库,这样可以在预先计算的点之间留出更短的间隔。这也将消除启动时在预计算表中读取的时间,但查找现在将涉及对文件系统的访问,这比内存读取花费的时间长得多。什么是最好的策略取决于预期的输入和它运行的系统。

如果上限不小,计算查找表将花费相当长的时间,但这是一次性成本。

如果预期输入较大,最多10 16 ,并且您不愿意花费必要的时间来预先计算该范围的查找表,最好的办法是实现一个对于素数计数函数的更好算法,Meissel's method as refined by Lehmer相对容易实现(不是那么容易,我将在这里给出一个示例实现,但here's a Haskell implementation可能有帮助)。更好,但更复杂的是由Miller et al改进的方法。

除此之外,你需要研究当前最先进的技术,并且可能应该使用比Python更低级的语言。

答案 1 :(得分:2)

你必须检查所有前面的候选人的素数。没有捷径。正如你所说,你可以缓存先前计算的结果并从那里开始,但这是你能做的最好的。