OSX意外地报告python退出并中止python

时间:2016-05-06 22:06:03

标签: python macos recursion

当我运行这个程序时,我创建了使用递归打印回文素数(不允许循环),苹果报告说python意外退出并中止和断开shell。然而,这只发生在相当大的输入上,例如在200 - 800之间。

这有什么理由吗?

我的代码是:

import sys
sys.setrecursionlimit(30000)
    def isprime(start,end,divisor):
        if start == end:
            return -1
        else:
            if divisor == start:
                a = str(start)
                b = str(start)[::-1]
                if a == b:
                    print(b)            
                return isprime(start+1,end,2)
            elif start%divisor == 0:
                return isprime(start+1,end,2)
            else:
                return isprime(start,end,divisor+1)     

    def main():
        n = eval(input('Enter the starting point N:''\n'))
        m = eval(input('Enter the ending point M:''\n'))
        divisor = 2
        print('The palindromic primes are:')
        primenumbers = isprime(n,m,divisor)

    main()

1 个答案:

答案 0 :(得分:1)

问题是你在大约20K递归的情况下耗尽了堆栈帧 - 你在400年代测试数字的时间达到了这个极限。即你为每个号码使用了太多的堆栈帧。改善这种情况的一种方法是测试更少的除数,因为每个除数都需要一个框架,并且我们的测试不仅仅是必要的。即当你应该测试2到sqrt(N)(甚至更少......)时,你要测试2到N

另一个问题是,尽管显式返回并且程序在结尾处期望值,但您不会返回任何有用的结果。这两个问题都在下面解决:

import sys
import math

sys.setrecursionlimit(30000)

def ispalindrome(x):
    y = str(x)
    return y == y[::-1]

def ispalindromeprime(start, end, divisor=2):

    palindrome_primes = []

    if start == end:
        pass

    elif divisor > int(math.sqrt(start)):
        if ispalindrome(start):
            print(start)  # optional
            palindrome_primes.append(start)     
        palindrome_primes.extend(ispalindromeprime(start+1, end))

    elif start % divisor == 0:
        palindrome_primes.extend(ispalindromeprime(start+1, end))

    else:
        palindrome_primes.extend(ispalindromeprime(start, end, divisor+1))

    return palindrome_primes

def main():
    n = int(input('Enter the starting point N: '))
    m = int(input('Enter the ending point M: '))

    print('The palindromic primes are:')
    numbers = ispalindromeprime(n, m)
    print(numbers)

if __name__ == "__main__":
    main()

这会将你的限制从400左右提高到2500左右,并返回回文素数列表:

Enter the starting point N: 2
Enter the ending point M: 2500
The palindromic primes are:
2
3
5
7
11
101
131
151
181
191
313
353
373
383
727
757
787
797
919
929
[2, 3, 5, 7, 11, 101, 131, 151, 181, 191, 313, 353, 373, 383, 727, 757, 787, 797, 919, 929]

我们可以通过减少我们测试的数字和我们测试的除数来进一步推动测试。即对待' 2'作为一个特例,只能使用奇数和除数:

def ispalindromeprime(start, end, divisor=3):

    palindrome_primes = []

    if start >= end:
        pass

    elif start % 2 == 0:
        if start == 2:
            print(start)  # optional
            palindrome_primes.append(start)     
        palindrome_primes.extend(ispalindromeprime(start+1, end))

    elif divisor > int(math.sqrt(start)):
        if ispalindrome(start):
            print(start)  # optional
            palindrome_primes.append(start)     
        palindrome_primes.extend(ispalindromeprime(start+2, end))

    elif start % divisor == 0:
        palindrome_primes.extend(ispalindromeprime(start+2, end))

    else:
        palindrome_primes.extend(ispalindromeprime(start, end, divisor+2))

    return palindrome_primes

虽然没有找到更多结果,但这会将你的限制提升到4500左右。 (虽然它确实提高了程序的速度。)

<强>更新

我们可以做得更好 - 将限制推到递归堆栈本身的极限。我们可以更容易地生成回文并测试它们是否为素数(其他代码保持不变),而不是生成质数并测试它们是否为回文序列:

def isprime(number, divisor=3):

    if number <= 2 or number % 2 == 0:
        return number == 2

    if divisor > int(math.sqrt(number)):
        return True

    if number % divisor == 0:
        return False

    return isprime(number, divisor+2)

def ispalindromeprime(n, m):

    palindromeprimes = []

    if n == m:
        return palindromeprimes

    if ispalindrome(n) and isprime(n):
        print(n)  # optional
        palindromeprimes.append(n)

    palindromeprimes.extend(ispalindromeprime(n+1, m))

    return palindromeprimes

现在我们可以超越之前的限制,即使使用递归解决方案:

Enter the starting point N: 1
Enter the ending point M: 20000
The palindromic primes are:
2
...
929
10301
10501
10601
11311
11411
12421
12721
12821
13331
13831
13931
14341
14741
15451
15551
16061
16361
16561
16661
17471
17971
18181
18481
19391
19891
19991
[2, 3, 5, 7, 11, 101, 131, 151, 181, 191, 313, 353, 373, 383, 727, 757, 787, 797, 919, 929, 10301, 10501, 10601, 11311, 11411, 12421, 12721, 12821, 13331, 13831, 13931, 14341, 14741, 15451, 15551, 16061, 16361, 16561, 16661, 17471, 17971, 18181, 18481, 19391, 19891, 19991]

由于我们只需要测试奇数(除2之外),我们可以再次加倍:

def ispalindromeprime(n, m):

    palindromeprimes = []

    if n > m:
        return palindromeprimes

    if ispalindrome(n) and isprime(n):
        print(n)  # optional
        palindromeprimes.append(n)

    if n == 1 or n % 2 == 0:
        n -= 1

    palindromeprimes.extend(ispalindromeprime(n+2, m))

    return palindromeprimes

获得更大的结果:

Enter the starting point N: 1
Enter the ending point M: 50000
The palindromic primes are:
2
...
19991
30103
30203
30403
30703
30803
31013
31513
32323
32423
33533
34543
34843
35053
35153
35353
35753
36263
36563
37273
37573
38083
38183
38783
39293
[2, 3, 5, 7, 11, 101, 131, 151, 181, 191, 313, 353, 373, 383, 727, 757, 787, 797, 919, 929, 10301, 10501, 10601, 11311, 11411, 12421, 12721, 12821, 13331, 13831, 13931, 14341, 14741, 15451, 15551, 16061, 16361, 16561, 16661, 17471, 17971, 18181, 18481, 19391, 19891, 19991, 30103, 30203, 30403, 30703, 30803, 31013, 31513, 32323, 32423, 33533, 34543, 34843, 35053, 35153, 35353, 35753, 36263, 36563, 37273, 37573, 38083, 38183, 38783, 39293]