素数生成器中的分段错误

发布于 2024-09-26 10:08:58 字数 898 浏览 3 评论 0原文

我知道以下不是生成素数列表的最快方法,但是我向自己提出了问题,并且在谷歌搜索之前编写了以下程序。对于数字 << ,它效果很好。 ~ 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

I am aware the following isn't the fastest way of generating a list of primes however I posed myself the problem and before googling wrote the following program. It works fine for numbers < ~ 44,000 but then gives a segmentation fault when ran on my 2Ghz Core 2 Duo Macbook. I am not really interested in alternative methods at the moment but in why its giving me a seg fault.

The last prime it is able to calculate is 42751 before it dies saying 'Segmentation fault'.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

吹泡泡o 2024-10-03 10:08:58

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

You might be getting stack overflow from too many recusive calls on the stack. At 42751 you would have a 21375 depth function call stack. In such case, refining your method might actually be needed.

A handy little routine which will check primeness can be written like this (pseudocode):

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;

This method works because of the following:

  1. If n is less than 2, it can't be prime
  2. If n is 2 or 3 it must be prime
  3. If n is not 2 or 3 but is divisible by either, it is not prime
  4. All prime numbers aside from 2 and 3 can be written in the form 6k+1 or 6k-1. If a number is prime, it is not evenly divisible by any other prime number. Only need to check up until the square root of n because anything more than that definitely does not divide evenly into n.
救赎№ 2024-10-03 10:08:58

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

Your program is using recursion. Every function call saves registers on to the stack and then jumps to the beginning of the function. Since your stack has a limited size, eventually you will run out of stack space. At this point you are you would be writing over memory you aren't supposed (or even allowed) to. Thus leading to a segmentation fault.

岛歌少女 2024-10-03 10:08:58

设置一个非常大的递归限制,然后递归一堆是导致 Python 崩溃的记录方法之一解释者。

本质上,你是在告诉Python,如果你递归得太远,不要阻止你,那么你就递归得太远了。

Setting a very large recursion limit and then recursing a bunch is one of the documented ways to crash the Python interpeter.

Essentially you're telling Python not to stop you if you recurse too far, and then you're recursing too far.

野心澎湃 2024-10-03 10:08:58

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

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

You're making a recursive call, counting up linearly by 2. CPython doesn't do tail call elimination, and (IIRC) it uses the C stack, so it's taking up some pretty serious stack space here.

I can't find the default stack size on 64-bit Mac OS (on 32-bit it appears to be 8MB) but it's definitely not infinite, and apparently not big enough to hold stack frames for every odd number up to 50,000.

沙沙粒小 2024-10-03 10:08:58

我的猜测是您在例程的递归部分中内存不足。

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

My guess is you have run out of memory in the recursive part of your routine.

If you recode it as a loop incrementing x then you will find it goes further before crashing.

漫雪独思 2024-10-03 10:08:58

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

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

For the sake of posterity the code that I wrote in the end which fixed the bug was as follows.

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()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文