【发布时间】:2011-05-31 12:21:29
【问题描述】:
我目前在 python 中检查数字素数的算法对于 1000 万到 10 亿之间的数字会变慢。我希望它得到改进,因为我知道我永远不会得到大于 10 亿的数字。
上下文是我无法获得足够快的实现来解决项目 Euler 的问题 60:我在 75 秒内得到问题的答案,而我需要在 60 秒内得到答案。 http://projecteuler.net/index.php?section=problems&id=60
我可以使用的内存很少,所以我无法存储所有低于 10 亿的素数。
我目前正在使用调整为 6k±1 的标准试用分区。还有什么比这更好的吗?对于这么大的数字,我是否已经需要使用 Rabin-Miller 方法。
primes_under_100 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
def isprime(n):
if n <= 100:
return n in primes_under_100
if n % 2 == 0 or n % 3 == 0:
return False
for f in range(5, int(n ** .5), 6):
if n % f == 0 or n % (f + 2) == 0:
return False
return True
如何改进这个算法?
精度:我是 python 新手,只想使用 python 3+。
最终代码
对于有兴趣的朋友,使用MAK的思路,我生成了如下代码,大约快了1/3,让我在不到60秒的时间内就得到了欧拉问题的结果!
from bisect import bisect_left
# sqrt(1000000000) = 31622
__primes = sieve(31622)
def is_prime(n):
# if prime is already in the list, just pick it
if n <= 31622:
i = bisect_left(__primes, n)
return i != len(__primes) and __primes[i] == n
# Divide by each known prime
limit = int(n ** .5)
for p in __primes:
if p > limit: return True
if n % p == 0: return False
# fall back on trial division if n > 1 billion
for f in range(31627, limit, 6): # 31627 is the next prime
if n % f == 0 or n % (f + 4) == 0:
return False
return True
【问题讨论】:
-
我知道它的名称是 Python 3 或 Python 3.1,但看起来 Py3k 引用了这些版本。
-
不应该是
f和f+4...你能确认一下吗?为什么4? -
更清楚的是,我使用基数 7 + 6k 而不是 5 + 6k 所以我需要使用 +0、+4、+6、+10 等而不是 +0、+2, +6,+8。优点是我不测试 31625。
-
警告:纯 python 示例(他的第一个 sn-p)不适用于所有素数。行
for f in range(5, int(n ** .5), 6):应该是for f in range(5, int(n ** .5) + 1, 6):;因为它在显示该数字可被自身的平方根整除之前(太早)退出。 -
@ogregoire:我不知道 Daniel 是否真的对你投了反对票,但我确实发现他的警告很有用,我几乎使用了第一个 sn-p,因为我只需要一个快速而肮脏的 isprime 函数和second 在 Python 2.x 上对我来说开箱即用 ;)
标签: python python-3.x primes