最快的可变数据持有者

时间:2013-03-27 16:20:18

标签: python arrays primes

我最近从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

我基本上是在寻找一个快速的数据持有者,这个数据持有者是可变的,可以保留TrueFalse

1 个答案:

答案 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]