我对Eratosthenes筛子的实施有缺陷吗?

时间:2012-11-21 05:25:50

标签: python function primes sieve

我正在用Python制作一个Eratosthenes的Sieve实现。出现的问题并非所有素数都出现(主要是编号较低的素数)。

这是我的代码:

def prevPrimes(n):
    from math import sqrt
    from time import time
    start = time()
    if type(n) != int and type(n) != long:
        raise TypeError("Arg (n) must be of <type 'int'> or <type 'long'>")
    if n <= 2:
        raise ValueError("Arg (n) must be at least 2")
    limit, x, num, primes = sqrt(n), 2, {}, []
    for i in range(1, n+1):
        num[i] = True
    while x < limit:
        for i in num:
            if i%x==0:
                num[i] = False
        x += 1
    for i in num:
        if num[i]:
            primes.append(i)
    end = time()
    primes = sorted(primes)
    print round((end - start), 2), ' seconds'
    return primes

如果我输入>>> prevPrimes(1000),我希望结果开头为:[2, 3, 5, 7, 11, 13, 17]等。但是,这就是它的样子:[1, 37, 41, 43, 47, #more numbers]

我知道问题在于它将{原始'素数(2,3,5,7,11,13,17等)称为False因为我的方式程序检查素数。我怎么能避免这个?在此先感谢:)

4 个答案:

答案 0 :(得分:1)

有时,当您遍历num时,x等于i,因此i % x等于0,i被标记为非素数

您需要在while循环中的某处添加if not x == i:,例如:

while x < limit:
        for i in num:
            if not x == i:
                if num[i] and i%x==0:
                    num[i] = False

答案 1 :(得分:1)

所以这不是一个真正的SoE实现,我刚才写的是下面的。

number_primes = 10
prime_list = [True]*number_primes

for i in range (2, number_primes):    #check from 2 upwards
  if prime_list[i]:                   #If not prime, don't need to bother about searching
    j = 2
    while j*i < number_primes:        # Filter out all factors of i (2...n * prime)
      prime_list[j*i] = False
      j+=1

答案 2 :(得分:1)

首先,回答您的具体问题。您丢弃的素数小于 n 的平方根。最简单的解决方法是在内循环结束时将行num[i] = False更改为num[i] = (not x == i)(我认为这样做有效,我还没有对其进行测试)。

其次,您的算法是试验分区,而不是Eratosthenes的Sieve,并且将具有时间复杂度O(n ^ 2)而不是O(n log log n)。模运算符让游戏消失。最简单的Eratosthenes Sieve看起来像这样(伪代码,你可以把它翻译成Python):

function primes(n)
  sieve := makeArray(2..n, True)
  for p from 2 to n step 1
    output p
    for i from p+p to n step p
      sieve[i] := False

有很多方法可以改进该算法。如果您对素数编程感兴趣,我谦虚地推荐this essay,其中包括一个优化的Eratosthenes Sieve,并在Python中实现。

答案 3 :(得分:0)

导入时间

def primes_sieve1():

limitn = int(raw_input("Please enter an upper limit ")) +1
start = time.clock()
primes = {
    }

for i in range(2, limitn):
    primes[i] = True

for i in primes:
    factors = range(i,limitn, i)
    for f in factors[1:]:
        primes[f] = False

end = time.clock()
print "This took ",end-start," seconds"
return [i for i in primes if primes[i]==True]

primes_sieve1()

此代码不是使用除法,而是将所有数字的倍数小于限制的根,并将它们更改为false。这有点快,因为它不涉及将每个数字除以其他数字。

同样低于1000的情况会发生这样的情况,即素数将自己模数为0,因此程序会认为它是假的。由于sqrt(1000)大约为31,因此小于31的素数将受到影响。

例如,在“while x&lt; limit”的第7个循环中,出现这样的情况: 7%7 == 0,因此在您的程序中7将显示为false。对于低于“while x&lt; limit”循环限制的所有素数,都会发生这种情况,因为x在某些时候会是你想要找到的素数。