Python Eratosthenes Sieve算法优化

时间:2012-01-28 07:54:35

标签: python optimization primes sieve-of-eratosthenes

我正在尝试实施Eratosthenes筛选。输出似乎是正确的(减去需要添加的“2”),但如果函数的输入大于100k左右,则似乎需要花费过多的时间。有什么方法可以优化这个功能?

def sieveErato(n):
     numberList = range(3,n,2)

     for item in range(int(math.sqrt(len(numberList)))):
            divisor = numberList[item]
            for thing in numberList:
                    if(thing % divisor == 0) and thing != divisor:
                            numberList.remove(thing)
    return numberList

6 个答案:

答案 0 :(得分:1)

你的算法不是Eratosthenes的Sieve。正如Eratosthenes在两千多年前所做的那样,你进行试验分裂(模数算子)而不是交叉倍数。 Here是对真正的筛选算法的解释,下面显示的是我简单直接的实现,它返回一个不超过 n 的素数列表:

def sieve(n):
    m = (n-1) // 2
    b = [True]*m
    i,p,ps = 0,3,[2]
    while p*p < n:
        if b[i]:
            ps.append(p)
            j = 2*i*i + 6*i + 3
            while j < m:
                b[j] = False
                j = j + 2*i + 3
        i+=1; p+=2
    while i < m:
        if b[i]:
            ps.append(p)
        i+=1; p+=2
    return ps

我们只筛选奇数,停在 n 的平方根处。 j 上的奇怪计算映射在 b中筛选3,5,7,9,...和索引0,1,2,3 ......的整数之间的映射位数组。

你可以在http://ideone.com/YTaMB看到这个功能,它可以在不到一秒的时间内将素数计算为一百万。

答案 1 :(得分:0)

你可以像Eratosthenes那样尝试。获取一个数组,其中包含您需要检查顺序升序所需的所有数字,转到数字2并标记它。现在抓住每秒的数字直到数组结束。然后转到3并标记它。之后,每隔三个数字划一次。然后转到4 - 它已被划伤,所以跳过它。对每个尚未划伤的n + 1重复此操作。

最后,标记的数字是最重要的数字。这种算法速度更快,但有时需要大量内存。您可以逐点优化它所有偶数(因为它们不是素数)并手动将2添加到列表中。这会使逻辑扭曲一点,但会占用一半的内存。

以下是我所说的内容:http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

答案 2 :(得分:0)

警告:在迭代迭代器时从迭代器中删除元素可能是贬义......

你可以制作

    if(thing % divisor == 0) and thing != divisor:

通过将它分成一个循环来测试打火机,当你到达'divisor'的索引然后测试时,它会断开:

for thing in numberList_fromDivisorOn:
    if(thing % divisor == 0):
        numberList.remove(thing)

答案 3 :(得分:0)

我按照@MAK的建议点了这个链接:Sieve of Eratosthenes - Finding Primes Python我发现接受的答案可以通过我在你的代码中找到的想法得到改善:

def primes_sieve2(limit):
    a = [True] * limit               # Initialize the primality list
    a[0] = a[1] = False
    sqrt = int(math.sqrt(limit))+1
    for i in xrange(sqrt):
        isprime = a[i]
        if isprime:
            yield i
            for n in xrange(i*i, limit, i):     # Mark factors non-prime
                a[n] = False
    for (i, isprime) in enumerate(a[sqrt:]):
        if isprime:
            yield i+sqrt

答案 4 :(得分:0)

如果给定无限的内存和时间,以下代码将打印所有素数。并且它将在不使用试验部门的情况下完成。它基于论文中的haskell代码:The Genuine Sieve of Eratosthenes by Melissa E. O'Neill

from heapq import heappush, heappop, heapreplace
def sieve():
    w = [2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10]
    for p in [2,3,5,7]: print p
    n,o = 11,0
    t = []
    l = len(w)
    p = n
    heappush(t, (p*p, n,o,p))
    print p
    while True:
        n,o = n+w[o],(o+1)%l
        p = n
        if not t[0][0] <= p:
            heappush(t, (p*p, n,o,p))
            print p
            continue
        while t[0][0] <= p:
            _, b,c,d = t[0]
            b,c = b+w[c],(c+1)%l
            heapreplace(t, (b*d, b,c,d))
sieve()

答案 5 :(得分:0)

此代码需要2秒才能生成小于10M的素数 (这不是我的,我在谷歌上找到了它)

def erat_sieve(bound):
    if bound < 2:
        return []
    max_ndx = (bound - 1) // 2
    sieve = [True] * (max_ndx + 1)
    #loop up to square root
    for ndx in range(int(bound ** 0.5) // 2):
        # check for prime
        if sieve[ndx]:
            # unmark all odd multiples of the prime
            num = ndx * 2 + 3
            sieve[ndx+num:max_ndx:num] = [False] * ((max_ndx-ndx-num-1)//num + 1)
    # translate into numbers
    return [2] + [ndx * 2 + 3 for ndx in range(max_ndx) if sieve[ndx]]