素数生成器中的分段错误
我知道以下不是生成素数列表的最快方法,但是我向自己提出了问题,并且在谷歌搜索之前编写了以下程序。对于数字 << ,它效果很好。 ~ 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可能会因堆栈上的重复调用过多而导致堆栈溢出。在 42751 处,您将拥有 21375 深度的函数调用堆栈。在这种情况下,实际上可能需要改进您的方法。
一个方便的检查素数的小例程可以这样写(伪代码):
该方法之所以有效,是因为:
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):
This method works because of the following:
您的程序正在使用递归。每个函数调用都会将寄存器保存到堆栈上,然后跳转到函数的开头。由于堆栈的大小有限,最终您将耗尽堆栈空间。此时,您将在不应该(甚至不允许)的记忆上进行写入。从而导致分段错误。
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.
设置一个非常大的递归限制,然后递归一堆是导致 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.
您正在进行递归调用,以 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.
我的猜测是您在例程的递归部分中内存不足。
如果你将它重新编码为一个递增 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.
为了后人的缘故,我最后编写的修复该错误的代码如下。
For the sake of posterity the code that I wrote in the end which fixed the bug was as follows.