我最近从here下载了bitarray模块,用于更快速的筛选,但结果很糟糕。
from bitarray import bitarray
from numpy import ones
from timeit import timeit
def sieve1(n = 1000000):
'''Sieve of Eratosthenes (bitarray)'''
l = (n - 1)/2; a = bitarray(l); a.setall(True)
for i in xrange(500):
if a[i]:
s = i+i+3; t = (s*s-3)/2; a[t:l:s] = False
return [2] + [x+x+3 for x in xrange(l) if a[x]]
def sieve2(n = 1000000):
'''Sieve of Eratosthenes (list)'''
l = (n - 1)/2; a = [True] * l
for i in xrange(500):
if a[i]:
s = i+i+3; t = (s*s-3)/2; u = l-t-1
a[t:l:s] = [False] * (u/s + 1)
return [2] + [x+x+3 for x in xrange(l)]
def sieve3(n = 1000000):
'''Sieve of Eratosthenes (numpy.ones)'''
l = (n - 1)/2; a = ones(l, dtype=bool)
for i in xrange(500):
if a[i]:
s = i+i+3; t = (s*s-3)/2; a[t:l:s] = False
return [2] + [x+x+3 for x in xrange(l)]
print timeit(sieve1, number=10)
print timeit(sieve2, number=10)
print timeit(sieve3, number=10)
结果如下 -
1.59695601594
0.666230770593
0.523708537583
bitarray
筛的速度是列表的两倍多。
有没有人有更好的阵列的建议?任何东西都应该比python list
更快,或者我认为。
numpy.ones
速度最快,但我不喜欢numpy
,因为它需要很长时间import
。
我基本上是在寻找一个快速的数据持有者,这个数据持有者是可变的,可以保留True
和False
。
答案 0 :(得分:2)
在bitarray中实际设置和清除位非常快。制作返回列表的速度较慢。不是迭代一个范围,然后测试每个位,而是利用bitarray支持迭代这些位。
试试这个:
def bitarray_sieve(n = 1000000):
'''Sieve of Eratosthenes (bitarray)'''
l = (n - 1)//2; a = bitarray(l); a.setall(True)
for i in range(500):
if a[i]:
s = i+i+3; t = (s*s-3)//2; a[t:l:s] = False
return [2] + [x+x+3 for x,b in enumerate(a) if b]
它在我的机器上运行大约0.38秒,而列表版本大约需要0.47秒。
你看过这个question吗?
我维护gmpy2并且我添加了迭代整数位和设置/清除位的能力。
以下示例大约需要0.16秒。
def gmpy2_sieve2(n=1000000):
'''Sieve of Eratosthenes (gmpy2, version 2)'''
l = (n - 1)//2; a = gmpy2.xbit_mask(l)
for i in range(500):
if a[i]:
s = i+i+3; t = (s*s-3)//2; u = l-t-1
a[t:l:s] = 0
return [2] + [x+x+3 for x in a.iter_set()]
瓶颈现在是计算x+x+3
。以下解决方案不会跳过筛选2.它需要两倍的内存,但它允许立即使用位位置。我的机器大约需要0.08秒:
def gmpy2_sieve(limit=1000000):
'''Returns a generator that yields the prime numbers up to limit.
Bits are set to 1 if their position is composite.'''
sieve_limit = gmpy2.isqrt(limit) + 1
limit += 1
# Mark bit positions 0 and 1 as not prime.
bitmap = gmpy2.xmpz(3)
# Process 2 separately. This allows us to use p+p for the step size
# when sieving the remaining primes.
bitmap[4 : limit : 2] = -1
# Sieve the remaining primes.
for p in bitmap.iter_clear(3, sieve_limit):
bitmap[p*p : limit : p+p] = -1
return list(bitmap.iter_clear(2, limit))
对于位的实际设置/清除,bitarray比gmpy2快。而bitarray具有gmpy2缺乏的许多功能。但是,我无法在bitarrary中找到更快的方法来获取设置或清除哪些位的索引。
顺便说一下,你的基准函数sieve2()和sieve3()返回不正确的结果;你遗失了if a[x]
。