A Fast Prime Number Sieve in Python
我一直在使用Eratosthenes的筛子来检查python中的素数生成,人们吹捧为相对较快的选择的解决方案,例如关于优化python中素数生成问题的一些答案中的解决方案,这些解决方案并不简单, 我在这里拥有的简单实现在效率上可以与它们匹敌。 我的实现如下
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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] |
定时执行返回
1 2 | python -m timeit -n10 -s"import euler""euler.sieve_for_primes_to(1000000)" 10 loops, best of 3: 19.5 msec per loop |
虽然上述链接问题的答案中描述的方法是python食谱中最快的方法,但下面给出了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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())) |
运行时给出
1 2 | python -m timeit -n10 -s"import euler""euler.get_primes_erat(1000000)" 10 loops, best of 3: 697 msec per loop |
我的问题是为什么人们会从烹饪书中大肆宣扬以上内容,因为它是理想的主要生成器?
我以最快的方式将您的代码转换为适合@unutbu的素数筛选比较脚本的方式,以列出N以下的所有素数
如下:
1 2 3 4 5 6 7 8 9 10 | 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在页面末尾)。
您只应使用该算法的"推迟"变体。比较您的代码测试运行上限分别为10和20百万
1 2 3 | ... print(len( [2] + [i*2+1 for i, v in enumerate(sieve_for_primes_to(10000000)) if v and i>0])) |
与另一个,分别以664579和1270607的素数运行,以生成
1 2 | ... print( list( islice( (p for p in postponed_sieve() ), n-1, n+1))) |
显示您的代码"仅"以3.1x ... 3.3x倍的速度运行。 :)速度不快36倍,因为您的计时出于某种原因而显示。
我认为没有人声称它是"理想的"主要生成器,只是它在概念上是干净清晰的。所有这些素数生成函数确实是玩具,无论如何,它们都使用完全不同的算法来处理大量数据。
在较低的范围内,重要的是算法的时间复杂度,应该在