素数发生器中的分段故障

时间:2010-10-07 20:52:19

标签: python segmentation-fault primes

我知道以下不是生成素数列表的最快方法,但是我自己提出问题并且在谷歌搜索之前编写了以下程序。它适用于数字< ~44,000但是在我的2Ghz Core 2 Duo Macbook上运行时会出现分段错误。我现在对替代方法并不感兴趣,但是为什么它给我一个段错误。

能够计算的最后一个素数是42751,然后才会说“分段错误”。

from sys import argv, exit, setrecursionlimit

def isPrime(no, halfNo, x = 3):

  # if counted through and all numbers from 3 too x are not factors is prime
  if x > halfNo:
    print no
    return 1

  # is x a factor?
  if no % x == 0:
    return 0
  else:
    isPrime(no, halfNo, x + 2)

path, limLow, limHigh = argv

limLow = int(limLow)
limHigh = int(limHigh)

setrecursionlimit(limHigh)

# negitive numbers, 0 and 1 are not primes so answer invalid
if limLow < 2:
  exit('Invalid input');

# if lower limit is even its not prime so increase by 1
if limLow % 2 == 0:
  limLow += 1

while (limLow <= limHigh):
  isPrime(limLow, limLow / 2)
  limLow += 2

6 个答案:

答案 0 :(得分:4)

您可能会从堆栈上过多的重复调用中获得堆栈溢出。在42751,你将有一个21375深度函数调用堆栈。在这种情况下,实际上可能需要改进您的方法。

一个方便的小程序将检查完整性可以这样写(伪代码):

if n < 2 return false;
if n == 2 or n == 3 return true;
if n % 2 == 0 return false;
if n % 3 == 0 return false;
for (i = 6; i < sqrt(n); i += 6) {
  if (n % (i - 1) == 0) return false;
  if (n % (i + 1) == 0) return false;
}
return true;

此方法的工作原理如下:

  1. 如果n小于2,则不能为素数
  2. 如果n为2或3则必须是素数
  3. 如果n不是2或3但可被任何一个整除,则不是素数
  4. 除了2和3之外的所有素数都可以用6k + 1或6k-1的形式写出。如果数字是素数,则它不能被任何其他素数整除。只需要检查直到n的平方根,因为除此之外的任何东西都不能均匀地分成n。

答案 1 :(得分:0)

您的程序正在使用递归。每个函数调用都会将寄存器保存到堆栈中,然后跳转到函数的开头。由于您的堆栈大小有限,最终您将耗尽堆栈空间。在这一点上,你是在写你不应该(甚至不允许)的记忆。从而导致分段错误。

答案 2 :(得分:0)

设置一个非常大的递归限制然后递归一堆是导致Python插件崩溃的documented方法之一。

基本上你告诉Python如果你做得太过分,就不要阻止你,然后你的回复太过分了。

答案 3 :(得分:0)

你正在进行递归调用,线性计数为2. CPython不执行尾调用消除,而(IIRC)它使用C堆栈,所以它在这里占用了一些相当严重的堆栈空间。

我无法在64位Mac OS上找到默认的堆栈大小(在32位上它似乎是8MB)但它绝对不是无限的,并且显然不足以容纳每个奇数的堆栈帧直到50000

答案 4 :(得分:0)

我的猜测是你的例行程序的递归部分内存不足。

如果你将它重新编码为一个递增x的循环,那么你会发现它在崩溃之前会更进一步。

答案 5 :(得分:0)

为了后人的缘故,我最后编写的修复错误的代码如下:

import sys

def isPrime( no ):
  sqrt = round(no**0.5);
  # if counted through and all numbers from 3 too x are not factors is prime
  if no % 2 == 0 or no % 3 == 0:
    return False
  for x in range(6, int(sqrt), 6):
    if no % (x - 1) == 0:
      return False
    if no % (x + 1) == 0:
      return False
  return True

def primesInRange(limLow, limHigh):
   # negitive numbers, 0 and 1 are not primes so answer invalid
  if limLow < 2:
    raise ValueError('Lower limit must be 2 or more')
  # if lower limit is even its not prime so increase by 1
  if limLow % 2 == 0:
    limLow += 1
  primes = []
  while (limLow <= limHigh):
    if isPrime(limLow): primes.append(limLow)
    limLow += 2
  return primes


def main():
  limLow = int(sys.argv[1])
  limHigh = int(sys.argv[2])
  print primesInRange(limLow, limHigh)

if __name__ == '__main__':
  main()