我的当前python质数检查算法对于在1000万和10亿之间的数字来说太慢了。我希望它能得到改进,尽管我知道我永远不会得到比10亿更大的数字。
背景是我无法得到一个足够快的实现来解决项目欧拉第60题:我在75秒内得到问题的答案,而我需要在60秒内得到它。http://projecteuler.net/index.php?section=problems&id=60
我手头可用的内存非常少,因此无法存储1亿以下的所有素数。
我目前正在使用调整为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
for f in range(5, int(n ** .5), 6):
这一行修改为for f in range(5, int(n ** .5) + 1, 6):
,因为它在能够显示该数字可被其平方根整除之前就退出了(也就是退出得过早)。 - deceleratedcaviar