OSX一直报告python意外退出并中止python

OSX一直报告python意外退出并中止python,python,macos,recursion,Python,Macos,Recursion,当我运行我创建的这个程序来使用递归打印回文素数(不允许循环)时,apple报告说python意外退出并中止并断开外壳的连接。然而,这只发生在输入量较大的情况下,比如在200-800之间 这有什么原因吗 我的代码是: import sys sys.setrecursionlimit(30000) def isprime(start,end,divisor): if start == end: return -1 else:

当我运行我创建的这个程序来使用递归打印回文素数(不允许循环)时,apple报告说python意外退出并中止并断开外壳的连接。然而,这只发生在输入量较大的情况下,比如在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()

问题是,在大约20K次递归时,堆栈帧用完了——大约在400次测试数字时达到了这个极限。即,每个数字使用的堆栈帧太多。一种改进的方法是测试更少的除数,因为每一个除数花费一帧,我们测试的比需要的更多。即,您正在测试2到N,而您应该测试2到sqrt(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左右,尽管它没有找到更多的结果。(尽管它确实提高了程序的速度。)

更新

我们可以做得更好——将限制提升到递归堆栈本身的限制。与生成素数并测试它们是否是回文不同,我们可以更轻松地生成回文并测试它们是否是素数(其他代码保持不变):

因为我们只需要测试奇数(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]

尝试直接在
Terminal.app
中运行,看看会发生什么。
sys.setrecursionlimit(30000)
-不要这样做。Python递归限制是为了保护您不受C级堆栈溢出的影响,这比Python堆栈溢出要混乱得多
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]