【问题标题】:My implementation of the Sieve of Eratosthenes is flawed?我的埃拉托色尼筛法有缺陷吗?
【发布时间】:2012-11-21 05:25:49
【问题描述】:

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

这是我的代码:

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

如果我输入&gt;&gt;&gt; prevPrimes(1000),我希望结果以:[2, 3, 5, 7, 11, 13, 17] 等开头。但是,它看起来是这样的:[1, 37, 41, 43, 47, #more numbers]

我知道问题在于它将“原始”素数(2、3、5、7、11、13、17 等)声明为 False,因为我的程序检查方式为素数。我怎样才能避免这种情况?在此先感谢:)

【问题讨论】:

  • 顺便说一句,这不是埃拉托色尼的筛子。真正的算法根本不使用%。这只是试用部门。

标签: python function primes sieve


【解决方案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】:

    有时当您遍历 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
    

    【讨论】:

    • 另外,虽然这很可能找到素数,但它并不是真正使用埃拉托色尼筛法,它更像是一种蛮力方法。
    【解决方案3】:

    首先,回答您的具体问题。您正在丢弃小于 n 平方根的素数。最简单的解决方法是在内部循环的末尾将num[i] = False 行更改为num[i] = (not x == i)(我认为这行得通,我还没有测试过)。

    其次,您的算法是试除法,而不是埃拉托色尼筛法,并且时间复杂度为 O(n^2) 而不是 O(n log log n)。模运算符放弃了游戏。最简单的埃拉托色尼筛法看起来像这样(伪代码,可以翻译成 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,它包括一个优化的埃拉托色尼筛,并在 Python 中实现。

    【讨论】:

      【解决方案4】:

      进口时间

      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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多