【问题标题】:Generating infinite prime number squence using generators使用生成器生成无限素数序列
【发布时间】:2018-11-08 08:33:53
【问题描述】:

我正在尝试使用 Eratosthenes 筛生成一个无限质数序列。这是代码:

def naturals()->int:
    '''Generate natural numbers indefinitely'''
    i = 1
    while True:
        yield i
        i = i+1

def primes():
    N = naturals()
    _ = next(N)#Pop out 1
    while True:
        n = next(N)
        yield n
        N = (i for i in N if i%n != 0)

但是,上面的生成器只产生 2,3,4... 那么我到底哪里出错了?

【问题讨论】:

  • 您必须在某处记录现有的主要因素。虽然我理解您的尝试,但如果它有效,out 将非常低效。
  • 即使你得到这个工作,它也不会是 Eratosthenes 的筛子。这将是审判部门。真正的埃拉托色尼筛法不涉及可分性检验。
  • @Kevin:不过,生成器在创建后永远不需要使用 N 变量。重新分配n 是一个更大的问题。
  • 实际上,我是通过查看在 Haskell 中实现此功能的计算机发烧友视频实现的。要么我理解错了,要么他们把它称为埃拉托色尼筛子是错误的。
  • naturals 只是itertools.count

标签: python generator


【解决方案1】:

一步一步来:

while True:
    n = next(N)

n 是 2。

    yield n
    N = (i for i in N if i%n != 0)

这会将N 包装在一个生成器中,该生成器会删除n 的倍数的值。请注意,我们说的是 n 的倍数,而不是 2 的倍数。

在下一个循环中,我们从naturals() 中获取下一个元素,得到3,将它与n 取模,即2,得到1,而不是0。所以我们将 3 分配给 n 并产生它。然后,我们将之前的 N 包装在另一个生成器中,它与之前的包装器所做的事情相同,这会减慢它的速度,但没有其他效果。

然后,在下一个循环中,我们从naturals() 中获取下一个元素,得到4,将它与n 取模,即3,得到1,即不为零。然后我们再次进行模数并得到相同的结果。所以我们将 4 分配给n 并生成它...

【讨论】:

  • 所以真正的问题在于重新分配n?
  • 问题是你没有在每次迭代中创建一个新变量,只是重复使用同一个变量。但是,您也可能会看到这种方法的性能很差,因为展开所有生成器需要时间。
  • 还因为它是试除法,而且因为它甚至不会在它正在测试的任何数字的平方根处停止试除法,并且因为巨大的生成器堆栈将在之后达到递归限制大约 1000 个素数。
【解决方案2】:

如果你对连续的划分检查感到满意,你可以实现更常见的版本:

  • 用 2 初始化序列
  • 从 3 开始,只检查奇数 ...
  • 如果N 不能被任何现有素数整除,
  • ...将其添加到素数列表并发出。
  • N 增加 2。

样式中的代码:

def primes():
    sofar = [2]
    n = 3
    yield 2

    while True:
        if all(n%i for i in sofar):
            sofar.append(n)
            yield n
        n += 2

这会在 N = 250,000 左右减慢到 100 个素数/秒,并从那里继续降级。

【讨论】:

  • 顺便说一句,我通过维护两个列表加快了 lot 的速度:一个包含所有素数 n 时,我检查是否需要将第二个列表中的最低素​​数移动到“检查”列表中。
猜你喜欢
  • 1970-01-01
  • 2014-12-04
  • 2016-10-12
  • 2015-07-14
  • 2018-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-22
相关资源
最近更新 更多