【问题标题】:Generator function for prime numbers [duplicate]素数的生成器函数
【发布时间】:2014-10-31 15:32:01
【问题描述】:

我正在尝试编写一个用于打印素数的生成器函数,如下所示

 def getPrimes(n):
    prime=True
    i=2
    while(i<n):
        for a in range(2,i):
            if(i%a==0):
                prime=False
                break
        if(prime):    
            yield i

但是我没有得到想要的结果 p=getPrimes(100) 应该给我一个生成器函数,它将迭代从 2 到 100 的素数,但我得到的结果是 [2,3]。我做错了什么?

【问题讨论】:

标签: python generator primes


【解决方案1】:

埃拉托色尼筛法:最有效的素数生成算法

取自这里:

Simple Prime Generator in Python - Eli Bendersky 的回答。

它标记了235711 的所有倍数。其余的都是素数。

def genprimes(limit): # derived from 
                      # Code by David Eppstein, UC Irvine, 28 Feb 2002
    D = {}            # http://code.activestate.com/recipes/117119/
    q = 2

    while q <= limit:
        if q not in D:
            yield q
            D[q * q] = [q]
        else:
            for p in D[q]:
                D.setdefault(p + q, []).append(p)
            del D[q]
        q += 1

p = genprimes(100)
prms = [i for i in p]

print prms

输出:

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

【讨论】:

  • 您能解释一下这是如何工作的吗?很有趣。
  • 效率不是最高,但也不错。
  • 至少cite your source 用于代码(或者您是否使用了Python cookbook recipe directly perhaps);删除 cmets 以将其声明为您自己的并不是那么好。顺便说一句,您在代码中留下了错误。
  • 请查看how to reference material written by others。您需要更准确地了解您的信用。
  • 请注意另一个答案中的代码如何在其来源的顶部包含注释?它包括一个明确的 URL,以及代码的作者。另请注意,D[q * q] 分配给,而不是 D[q * 2]
【解决方案2】:

您需要将 prime 重置为 True 作为 while 块内的第一条语句,而不是之前的语句。事实上,一旦你找到一个合数,prime 将永远不会再为真,因此你将永远不会产生更多的数字。

【讨论】:

    【解决方案3】:

    您有几个错误,请参阅 cmets:

    def getPrimes(n):
        i = 2
        while i < n :
            prime = True # reset the `prime` variable before the inner loop
            for a in xrange(2, i):
                if i%a == 0:
                    prime = False
                    break
            if prime:    
                yield i
            i += 1 # don't forget to advance `i`
    

    现在,为了更好地处理边缘情况,执行更少的迭代并生成小于n 参数值的素数序列:

    def getPrimes(n):
        if n <= 2:
            raise StopIteration
        yield 2
        for i in xrange(3, n, 2):
            for x in xrange(3, int(i**0.5)+2, 2):
                if not i % x:
                    break
            else:
                yield i
    

    无论哪种方式,代码都按预期工作:

    [x for x in getPrimes(20)]
    => [2, 3, 5, 7, 11, 13, 17, 19]
    

    【讨论】:

      【解决方案4】:
      def isprime(n):
          for i in range(2 ,int((n**0.5))+1):
              if n % i == 0:
                  return False
          return True
      
      def getPrimes(n):
          yield 2
          i = 1
          while i <= n-2:
              i += 2
              if isprime(i):
                  yield i
      

      【讨论】:

        【解决方案5】:

        作为Istvan Chung answered,您的问题来自您从未重置prime 标志这一事实。但是,我建议使用替代解决方案,而不是直接解决该问题。

        与其使用标志变量来检测您何时通过循环而没有碰到break,不如在循环之后使用else 块:

        def getPrimes(n):
            i = 2
            while i < n :
                for a in range(2, i):
                    if i % a == 0:
                        break
                else:    
                    yield i
        

        else 块将在循环完成时运行,而不是被break 语句提前停止。

        您可以通过仅测试素数除数而不是所有小于i 的整数来进一步改进这一点。这是一种使用递归的方法(另一种方法是保留先前计算的素数列表,但如果n 非常大,则可能需要大量存储空间):

        def getPrimes(n):
            yield 2
            i = 3
            while i < n:
                for a in getPrimes(int(math.sqrt(i))+1):
                    if i % a == 0:
                        break
                else:
                    yield i
                i += 2
        

        【讨论】:

        • in for a in getPrimes(int(math.sqrt(i))+1): getPrimes 将为每个 i 计算。相反,您可以将以前的素数列表only 保留到nsqrt,并使用it 来测试is在 sqrt 上方。
        • 我不知道你也可以在循环语句上使用 else
        猜你喜欢
        • 2013-03-20
        • 1970-01-01
        • 1970-01-01
        • 2019-09-10
        • 2017-02-18
        • 1970-01-01
        • 1970-01-01
        • 2019-09-06
        • 2014-01-11
        相关资源
        最近更新 更多