我正在尝试学习python,我认为尝试开发自己的主筛将是下午的一个有趣的问题。到目前为止需要时,我只会导入我在网上找到的Eratosthenes筛选版本 - 这就是我用作我的基准。
在尝试了几种不同的优化后,我以为我写了一个相当不错的筛子:
def sieve3(n):
top = n+1
sieved = dict.fromkeys(xrange(3,top,2), True)
for si in sieved:
if si * si > top:
break
if sieved[si]:
for j in xrange((si*2) + si, top, si*2): [****]
sieved[j] = False
return [2] + [pr for pr in sieved if sieved[pr]]
使用前1,000,000个整数作为我的范围,此代码将生成正确数量的素数,并且仅比我的基准测试慢约3-5倍。当我在更大的范围内尝试它时,我正要放弃并拍拍自己的背部,但它已经不再有用了!
n = 1,000 -- Benchmark = 168 in 0.00010 seconds
n = 1,000 -- Sieve3 = 168 in 0.00022 seconds
n = 4,194,304 -- Benchmark = 295,947 in 0.288 seconds
n = 4,194,304 -- Sieve3 = 295,947 in 1.443 seconds
n = 4,194,305 -- Benchmark = 295,947 in 3.154 seconds
n = 4,194,305 -- Sieve3 = 2,097,153 in 0.8465 seconds
我认为这个问题来自于[****]
的问题,但我无法弄清楚它为什么会如此破碎。它应该将'j'的每个奇数倍标记为False并且它大部分时间都有效,但对于4,194,304以上的任何东西,筛子都会被破坏。 (公平地说,它也会随机打破其他数字,例如10,000)。
我做了一个更改,它显着减慢了我的代码,但它实际上适用于所有值。此版本包括所有数字(不仅仅是赔率),但在其他方面相同。
def sieve2(n):
top = n+1
sieved = dict.fromkeys(xrange(2,top), True)
for si in sieved:
if si * si > top:
break
if sieved[si]:
for j in xrange((si*2), top, si):
sieved[j] = False
return [pr for pr in sieved if sieved[pr]]
任何人都可以帮我弄清楚为什么我的原始功能(sieve3)不能始终如一地工作吗?
编辑:我忘了提及,当Sieve3'打破'时,sieve3(n)返回n / 2。
答案 0 :(得分:2)
筛子需要对候选素数的循环进行排序。有问题的代码是枚举字典的键,这些键不保证是有序的。相反,请继续使用您用于初始化主筛选字典的xrange
以及返回结果循环,如下所示:
def sieve3(n):
top = n+1
sieved = dict.fromkeys(xrange(3,top,2), True)
for si in xrange(3,top,2):
if si * si > top:
break
if sieved[si]:
for j in xrange(3*si, top, si*2):
sieved[j] = False
return [2] + [pr for pr in xrange(3,top,2) if sieved[pr]]
答案 1 :(得分:1)
这是因为没有订购字典键。有时,for si in sieved:
偶然会按顺序循环遍历您的密钥。
在上一个例子中,第一个值得到的值足以立即打破循环。
你可以简单地使用: for si in sorted(sieved):
答案 2 :(得分:0)
好吧,看看运行时 - 你看到你显示的最后一个案例的运行时间几乎是基准测试的5倍,而它通常慢了5倍。那么这是一个红旗,也许你没有执行所有的迭代? (它的速度快了5倍,而质量几乎是原来的10倍......)
我现在没有时间更多地查看代码,但我希望这会有所帮助。