【问题标题】:Segmentation fault in Prime Number generator素数生成器中的分段错误
【发布时间】:2010-10-07 20:52:19
【问题描述】:

我知道以下不是生成素数列表的最快方法,但是我提出了自己的问题,并且在谷歌搜索之前编写了以下程序。它适用于

它能够计算的最后一个素数是 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

【问题讨论】:

  • 方法我指的是计算方法(即我没有使用筛算法)而不是递归函数中的方法。循环或其他方法。很抱歉造成混乱。

标签: python segmentation-fault primes


【解决方案1】:

您可能会因堆栈上的重复调用过多而导致堆栈溢出。在 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。

【讨论】:

  • @Shynthriir :抱歉,无法抗拒双关语。由于堆栈溢出,他陷入堆栈溢出。 :)
  • 我想指出同样的讽刺,但我想现在我会坚持这一点。
  • 我认为使用递归函数很聪明。你会建议一个简单的循环作为我的问题的答案吗?
  • 编辑了我的答案以包含一个不错的小素数检查方法。希望对您有所帮助。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    设置一个非常大的递归限制,然后递归一堆是documented 使 Python 解释器崩溃的方法之一。

    基本上你是在告诉 Python 如果你递归太远不要阻止你,然后你递归太远了。

    【讨论】:

      【解决方案4】:

      您正在进行递归调用,以 2 为单位线性计数。CPython 不进行尾调用消除,并且 (IIRC) 它使用 C 堆栈,因此它在这里占用了一些相当严重的堆栈空间。

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

      【讨论】:

        【解决方案5】:

        我猜你的例程递归部分内存不足。

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

        【讨论】:

          【解决方案6】:

          为了后代,我最后编写的修复错误的代码如下。

          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()
          

          【讨论】:

            猜你喜欢
            • 2012-04-05
            • 1970-01-01
            • 1970-01-01
            • 2023-03-22
            • 2016-01-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多