在Python中查找素数不一致性

在Python中查找素数不一致性,python,primes,sieve,Python,Primes,Sieve,我正在尝试学习python,我想尝试开发自己的prime sieve将是下午一个有趣的问题。到目前为止,当需要的时候,我只需要导入我在网上找到的Eratosthenes筛的一个版本——我用这个作为基准 在尝试了几种不同的优化之后,我认为我已经编写了一个相当不错的筛选: def sieve3(n): top = n+1 sieved = dict.fromkeys(xrange(3,top,2), True) for si in sieved: if si * si > top:

我正在尝试学习python,我想尝试开发自己的prime sieve将是下午一个有趣的问题。到目前为止,当需要的时候,我只需要导入我在网上找到的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]]
使用前1000000个整数作为我的范围,这段代码将生成正确数量的素数,并且只比我的基准测试慢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,并且在大多数情况下都有效,但是对于4194304以上的任何东西,筛子都会被打破。(公平地说,它也会在其他随机数上断裂,比如10000)

我做了一个更改,这大大降低了我的代码速度,但它实际上适用于所有值。这个版本包括所有数字(不仅仅是赔率),但在其他方面是相同的

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)不能一直工作吗


编辑:我忘了提到,当sive3‘中断’时,sive3(n)返回n/2

好吧,看看运行时——您会看到,您所展示的上一个案例中的运行时几乎比基准测试快5倍,而它通常慢5倍。这是一个危险信号,也许你没有执行所有的迭代?(它的速度快了5倍,而素数却几乎是原来的10倍……)


我现在没有时间进一步研究代码,但我希望这能有所帮助

这是因为字典键没有排序。偶尔,si in sieved:的
会以递增的顺序循环您的密钥。
在上一个示例中,si获得的第一个值足够大,可以立即中断循环

您可以简单地使用:
对于排序(筛选)中的si:

筛选要求对候选素数进行循环排序。所讨论的代码是枚举字典中的键,这些键不保证是有序的。相反,请继续使用
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]]

是的,我想我忘了提到,当它不工作时,sive3(n)=n/2,所以它一定跳过了一堆循环。我仍然不明白为什么…枚举dict的键不能保证是有序的,所以将si in sorted(sieved.keys())的循环更改为
,这确实起到了作用。。我想我得弄清楚它为什么会偶尔失效。我可以把一个评论标记为正确答案吗?如果没有,请随意添加答案,我很乐意接受。谢谢这是一个很难发现的错误。为了进行优化,您可能希望在主筛选循环和最终返回数组(而不是字典键)的xrange(3,top,2)上循环,因为这两个循环都应该排序。如果使用数组而不是字典,这可能会更快。Initialize sieved=[True]*top,那么数组的第i个元素表示数字2i+3。