在Python中发现Prime Sieve不一致

时间:2013-04-19 22:53:33

标签: python primes sieve

我正在尝试学习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。

3 个答案:

答案 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倍......)

我现在没有时间更多地查看代码,但我希望这会有所帮助。