【问题标题】:Python while loop won't exit (Beginner)Python while 循环不会退出(初学者)
【发布时间】:2015-07-14 15:07:16
【问题描述】:

最后的while 循环没有退出,我不知道为什么。

import sys

def is_prime(n):
    if n == 3:
        return True
    elif n == 4:
        return False
    else:
        for i in xrange(2,n):
            if n % i == 0:
                return False
        return True

primes = [2, 3]

counter = int(raw_input("Which prime number would you like to find? "))

while len(primes) < counter:
    for i in xrange(primes[-1], sys.maxint):
        if is_prime(i):
            primes.append(i)

print(primes[-1])

【问题讨论】:

标签: python while-loop


【解决方案1】:

它不会退出的原因是因为您对潜在素数的搜索空间太大了。你的桌面没那么快!他们有超级计算机试图计算这些东西。

for i in xrange(primes[-1], sys.maxint):

首先,尝试将其更改为更合理的内容:

for i in xrange(primes[-1], 10000):

你会看到你的循环确实退出了。

编辑:

您可以为这个问题添加一些不错的优化。首先,您应该增加 2 以跳过所有偶数:

for i in xrange(primes[-1], sys.maxint, 2):

其次,您只需要测试不超过潜在质数的平方根的除数。

for i in xrange(2,n**(0.5)):

原因是任何两个乘积为n 的数字,其中一个总是小于n 的平方根 - 因此,如果您在点击时还没有找到除数n 的平方根,你可以停止。这大大减少了您对更大数字的搜索空间。

【讨论】:

  • 这不是真正的问题,也不是一个很好的解决方案,因为这意味着获得第 8 个素数与获得第 1229 个素数一样昂贵,而获得第 1230 个素数将进入无限循环。
  • 知道了!问题是我不知道在每次 for 循环迭代结束时不会检查 while 条件。我从来没有试图找到那么多个素数。在primes.append(i) 之后简单添加break 解决了它,即使范围很荒谬。学过的知识。谢谢!
  • @abarnert - 你是对的。我错过了他试图找到特定质数的部分,而不是全部。你能简单地扩展一下进入无限循环的第 1230 个素数吗?
  • @MartinKonecny:第 1230 个素数是 10007。所以,外循环会看到你只有 1229 个素数,内循环会从 9974 到 10000 并且看不到新的素数并退出,外循环会看到你只有 1229 个素数,无穷无尽。
  • 虽然我认为他还有另一个错误,他每次都会继续将9973 附加到列表中,在这种情况下,他实际上返回,只是带有错误的数字(对于任何 >1229 的输入,它将返回 9973)。
【解决方案2】:

正如Martin Konecny's answer 解释的那样,您的循环需要计算直到sys.maxint 的所有素数,这需要非常非常长的时间(尤其是在64 位平台上!)。

但实际上,您并不需要素数最高为sys.maxint,甚至素数最高为 10000。使用他的解决方案,您将计算前 1229 个素数,即使您只需要前 7 个,这意味着它需要的时间比必要的要长。更糟糕的是,即使您需要第 1400 个素数,您会计算前 1229 个素数,这意味着您最终会陷入无限循环,永远寻找 10000 以下的下一个素数,即使存在不再是 10000 以下的素数。

这里的关键是尽快跳出循环,这样你就可以回到循环了。内部循环正在检查您是否有一个 足够大 质数,这与您的问题无关;外部循环正在检查您是否有 足够 个素数。所以你想在你找到的每个素数之后检查外循环。

一种方法是更改​​内部循环,使其在一个素数之后仅breaks 出来,让您有机会再次检查len

while len(primes) < counter:
    for i in xrange(primes[-1], sys.maxint):
        if is_prime(i):
            primes.append(i)
            break

事实上,如果你这样做,你甚至可以用一个无限范围来代替限制,它仍然会完成。

还有一件事:你在内部循环中有一个错误:xrange(primes[-1], sys.maxint) 包括primes[-1]primes[-1] 显然是素数。所以,你只会一遍又一遍地附加相同的值。你需要一个+ 1

所以:

while len(primes) < counter:
    for i in itertools.count(primes[-1]+1)
        if is_prime(i):
            primes.append(i)
            break

解决此问题的更好方法是使用真正的素筛而不是除数测试。筛子有效地保留了迄今为止找到的每个素数的下一个倍数的前瞻映射,因此如果您已经检查了 N-1 之前的所有值,您可以非常快速地确定 N 是否为素数。但这样做是一个更大的答案。 :)

【讨论】:

  • 谢谢,我不知道while 条件不会在每次for 循环迭代结束时得到检查。 “本地与全球”总是让我着迷。 break 解决了一切。非常感谢。
  • @conjenks:是的,只有在整个 for 循环完成后才会检查它。 while 无法“进入”其块内的代码并在其条件变为假时立即中断,它只是检查条件,运行整个块,然后重复。
猜你喜欢
  • 1970-01-01
  • 2016-04-14
  • 1970-01-01
  • 2015-08-15
  • 2013-09-26
  • 1970-01-01
  • 2021-02-26
  • 1970-01-01
  • 2018-12-21
相关资源
最近更新 更多