由于我开始掌握 Python 的窍门,因此我开始在 projecteuler.net 上测试我新获得的 Python 技能以解决一些问题。
无论如何,在某些时候,我最终制作了一个函数来获取所有素数的列表,直到数字“n”。
这是函数的外观:
def primes(n):
"""Returns list of all the primes up until the number n."""
# Gather all potential primes in a list.
primes = range(2, n + 1)
# The first potential prime in the list should be two.
assert primes[0] == 2
# The last potential prime in the list should be n.
assert primes[-1] == n
# 'p' will be the index of the current confirmed prime.
p = 0
# As long as 'p' is within the bounds of the list:
while p < len(primes):
# Set the candidate index 'c' to start right after 'p'.
c = p + 1
# As long as 'c' is within the bounds of the list:
while c < len(primes):
# Check if the candidate is divisible by the prime.
if(primes[c] % primes[p] == 0):
# If it is, it isn't a prime, and should be removed.
primes.pop(c)
# Move on to the next candidate and redo the process.
c = c + 1
# The next integer in the list should now be a prime,
# since it is not divisible by any of the primes before it.
# Thus we can move on to the next prime and redo the process.
p = p + 1
# The list should now only contain primes, and can thus be returned.
return primes
它似乎工作正常,尽管有一件事情让我感到困扰。在评论代码的时候,这一段突然显得不对劲:
# Check if the candidate is divisible by the prime.
if(primes[c] % primes[p] == 0):
# If it is, it isn't a prime, and should be removed from the list.
primes.pop(c)
# Move on to the next candidate and redo the process.
c += 1
如果候选不能被素数整除,我们检查位于'c + 1'的下一个候选。没问题。
但是,如果候选者可以被素数整除,我们首先将其弹出,然后检查位于“c + 1”处的下一个候选者。让我感到震惊的是,在弹出之后,下一个候选人不是位于'c + 1',而是位于'c',因为在弹出'c'之后,下一个候选人“落入”该索引。
然后我认为该块应该如下所示:
# If the candidate is divisible by the prime:
if(primes[c] % primes[p] == 0):
# If it is, it isn't a prime, and should be removed from the list.
primes.pop(c)
# If not:
else:
# Move on to the next candidate.
c += 1
上面的这个块对我来说似乎更正确,但让我想知道为什么原来的部分显然工作得很好。
所以,这是我的问题:
在弹出一个结果不是素数的候选人之后,我们可以假设,就像在我的原始代码中一样,下一个候选人不能被同一个素数整除吗?
如果是这样,那是为什么?
建议的“安全”代码是否会对在“不安全”代码中跳过的候选者进行不必要的检查?
PS:
我尝试将上述假设作为断言写入“不安全”函数,并使用 n = 100000 对其进行测试。没有发生问题。这是修改后的块:
# If the candidate is divisible by the prime:
if(primes[c] % primes[p] == 0):
# If it is, it isn't a prime, and should be removed.
primes.pop(c)
# If c is still within the bounds of the list:
if c < len(primes):
# We assume that the new candidate at 'c' is not divisible by the prime.
assert primes[c] % primes[p] != 0
# Move on to the next candidate and redo the process.
c = c + 1