【问题标题】:A Fast Prime Number Sieve in PythonPython 中的快速素数筛
【发布时间】:2013-04-06 22:21:24
【问题描述】:

我一直在使用 Eratosthenes 的筛子在 python 中生成素数,人们吹捧为相对较快的选项的解决方案,例如 the answers to a question on optimising prime number generation in python 中的一些解决方案并不简单,我在这里的简单实现在效率上与他们匹敌。下面给出了我的实现

def sieve_for_primes_to(n):
    size = n//2
    sieve = [1]*size
    limit = int(n**0.5)
    for i in range(1,limit):
        if sieve[i]:
            val = 2*i+1
            tmp = ((size-1) - i)//val 
            sieve[i+val::val] = [0]*tmp
    return sieve


print [2] + [i*2+1 for i, v in enumerate(sieve_for_primes_to(10000000)) if v and i>0]

定时执行返回

python -m timeit -n10 -s "import euler" "euler.sieve_for_primes_to(1000000)"
10 loops, best of 3: 19.5 msec per loop

虽然上面链接问题的答案中描述的方法是python食谱中最快的方法,但下面给出了

import itertools
def erat2( ):
    D = {  }
    yield 2
    for q in itertools.islice(itertools.count(3), 0, None, 2):
        p = D.pop(q, None)
        if p is None:
            D[q*q] = q
            yield q
        else:
            x = p + q
            while x in D or not (x&1):
                x += p
            D[x] = p

def get_primes_erat(n):
  return list(itertools.takewhile(lambda p: p<n, erat2()))

运行时会给出

python -m timeit -n10 -s "import euler" "euler.get_primes_erat(1000000)"
10 loops, best of 3: 697 msec per loop

我的问题是,为什么人们从烹饪书中吹捧上述相对复杂的理想素数生成器?

【问题讨论】:

  • 谁和在哪里吹捧erat2“作为理想的主要发电机”?请提供参考资料,以便我们更好地了解您提出问题的背景。
  • 您是否将您的算法与rwh_primes2 算法进行了比较?
  • erat2 仅与该页面上的 OP 代码进行了比较,而 Alex Martelli 仅表示 Cookbook 解决方案的速度是 OP 解决方案的两倍。与rwh_primes2相比,您的解决方案速度要慢两倍。
  • 这看起来像是 rwh_primes1 的一个小变化。

标签: python algorithm primes sieve-of-eratosthenes


【解决方案1】:

我将您的代码转换为适合@unutbu 在Fastest way to list all primes below N 的主筛比较脚本 如下:

def sieve_for_primes_to(n):
    size = n//2
    sieve = [1]*size
    limit = int(n**0.5)
    for i in range(1,limit):
        if sieve[i]:
            val = 2*i+1
            tmp = ((size-1) - i)//val 
            sieve[i+val::val] = [0]*tmp
    return [2] + [i*2+1 for i, v in enumerate(sieve) if v and i>0]

在我的 MBPro i7 上,该脚本快速计算所有小于 1000000 的素数,但实际上比 rwh_primes2、rwh_primes1 (1.2)、rwh_primes (1.19) 和 primeSieveSeq (1.12) 慢 1.5 倍(页面末尾的@andreasbriese)。

【讨论】:

    【解决方案2】:

    您应该只使用"postponed" variant of that algorithm。比较您的代码test run 上限为 10 和 2000 万,如

    ...
    print(len( [2] + [i*2+1 for i, v in 
      enumerate(sieve_for_primes_to(10000000)) if v and i>0]))
    

    与另一个,run at对应的664579和1270607个素数产生,为

    ...
    print( list( islice( (p for p in postponed_sieve() ), n-1, n+1))) 
    

    显示您的代码运行速度“仅”3.1x...3.3x 倍。 :) 不是 36x 倍,因为您的时间显示出于某种原因。

    我认为没有人声称它是一个“理想的”素数生成器,只是说它是一个概念上干净且清晰的生成器。所有这些素数生成函数实际上都是玩具,真正的东西是处理非常大的数字,无论如何使用完全不同的算法。

    这里在低范围内,重要的是算法的时间复杂度,它应该在~ n^(1+a)a &lt; 0.1...0.2empirical orders of growth 左右,它们看起来确实如此。拥有一个具有~ n^1.5 甚至~ n^2 增长顺序的玩具发电机玩起来并不好玩。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-31
      • 2011-09-22
      • 1970-01-01
      • 2017-12-11
      • 1970-01-01
      • 1970-01-01
      • 2010-10-31
      • 1970-01-01
      相关资源
      最近更新 更多