Python 如何使用超过极限位的递归?

Python 如何使用超过极限位的递归?,python,python-3.x,recursion,Python,Python 3.x,Recursion,我想用下面的程序进行递归,但因为输入数字太大(19位)。它在我的程序中抛出一个错误 内存错误:堆栈溢出或递归错误:在比较中超过最大递归深度。我尝试使用 import sys sys.setrecursionlimit(100000) 但这没有帮助。你有什么办法来处理这么大的数字吗? 这是我的全部计划 def recursion(n): return 1 if n < 2 else n * recursion(n - 2) string = str(recursion(1000

我想用下面的程序进行递归,但因为输入数字太大(19位)。它在我的程序中抛出一个错误 内存错误:堆栈溢出递归错误:在比较中超过最大递归深度。我尝试使用

import sys
sys.setrecursionlimit(100000)
但这没有帮助。你有什么办法来处理这么大的数字吗? 这是我的全部计划

def recursion(n):
    return 1 if n < 2 else n * recursion(n - 2)


string = str(recursion(1000000000000000000))
def递归(n):
如果n<2则返回1,否则返回n*递归(n-2)
string=str(递归(10000000000000000000000))
不幸的是,迭代失败了。但你可以自己做:

def recursion(n):
    result = 1
    for i in range(2, n+1, 2):
        result *= i
    return result
如果您真的希望它是递归的,那么您唯一能做的就是增加递归限制和堆栈大小,但这不是一个好主意。

不幸的是,这不利于迭代。但你可以自己做:

def recursion(n):
    result = 1
    for i in range(2, n+1, 2):
        result *= i
    return result

如果您真的希望它是递归的,那么您唯一能做的就是增加递归限制和堆栈大小,但这不是一个好主意。

这是递归的实际限制之一

Python可以防止递归调用的次数,以避免堆栈溢出。这是您看到的
递归错误

Python 3.7.4 (default, Aug 13 2019, 20:35:49) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def recursion(n):
...     return 1 if n < 2 else n * recursion(n - 2)
... 
>>> 
>>> string = str(recursion(1000000000000000000))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in recursion
  File "<stdin>", line 2, in recursion
  File "<stdin>", line 2, in recursion
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded in comparison
Python中解决此问题的惯用方法是使用迭代:

def iteration(n):
    result = 1
    for i in range(n, 1, -2):
        result *= i
    return result
不过,使用原始输入(
1e18
)运行此示例不会很快终止。随着整数的增长,计算所需的时间越来越长,因为操作需要使用大于64位的整数表示(或CPU能够用单个寄存器表示的位数)


然而,这将是这个问题的python解决方案。

这是递归的实际限制之一

Python可以防止递归调用的次数,以避免堆栈溢出。这是您看到的
递归错误

Python 3.7.4 (default, Aug 13 2019, 20:35:49) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def recursion(n):
...     return 1 if n < 2 else n * recursion(n - 2)
... 
>>> 
>>> string = str(recursion(1000000000000000000))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in recursion
  File "<stdin>", line 2, in recursion
  File "<stdin>", line 2, in recursion
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded in comparison
Python中解决此问题的惯用方法是使用迭代:

def iteration(n):
    result = 1
    for i in range(n, 1, -2):
        result *= i
    return result
不过,使用原始输入(
1e18
)运行此示例不会很快终止。随着整数的增长,计算所需的时间越来越长,因为操作需要使用大于64位的整数表示(或CPU能够用单个寄存器表示的位数)


然而,这将是这个问题的Pythonic解决方案。

即使是
n
,您的函数也会计算
2*4*6**n
。很容易计算出这与
2^(n/2)*(n/2)。例如,
2*4*6*8*10=(2*1)*(2*2)*(2*3)*(2*4)*(2*5)
,这就是
2^5*(1*2*3*4*5)=32*5。这可以通过函数快速有效地计算:

import math

def f(n):
    k = n//2
    return 2**k * math.factorial(k)
对于奇数
n
,它稍微复杂一些。从数学溢出中看


由,
f(n)
渐近等价于
sqrt(pi*n)*(n/e)^(n/2)
。插入
n=10^18
,并获取结果的base-2日志,您可以看到
f(10^18)
大约需要3.6才能存储结果的整数(这可能比您的计算机所能处理的还要多)。

即使
n
,您的函数也会计算
2*4*6**n
。很容易计算出这与
2^(n/2)*(n/2)。例如,
2*4*6*8*10=(2*1)*(2*2)*(2*3)*(2*4)*(2*5)
,这就是
2^5*(1*2*3*4*5)=32*5。这可以通过函数快速有效地计算:

import math

def f(n):
    k = n//2
    return 2**k * math.factorial(k)
对于奇数
n
,它稍微复杂一些。从数学溢出中看


由,
f(n)
渐近等价于
sqrt(pi*n)*(n/e)^(n/2)
。插入
n=10^18
,并获取结果的base-2日志,您可以看到
f(10^18)
大约需要3.6才能存储结果的整数(这可能超出了计算机的处理能力).

有时递归不是一种有用的方法。除了递归之外,您还有其他方法可供我使用的建议吗?如果您遇到内存错误,并且您的实现是正确的,这几乎肯定意味着您需要更改为非递归方法。10^19递归深度在任何现有计算机上都是不可能的即使除了递归限制问题,我怀疑您是否有内存来保存
str(递归(10000000000000000))
或计算
递归(10000000000000000)
。使用对数可以验证所涉及的内存是否过大。您试图计算的函数比任何指数函数都增长得快。有时递归不是一种有用的方法。除了递归之外,您还有其他方法可供我使用的建议吗?如果您遇到内存错误,并且您的实现是正确的,这几乎肯定意味着您需要更改为非递归方法。10^19递归深度在任何现有计算机上都是不可能的即使除了递归限制问题,我怀疑您是否有内存来保存
str(递归(10000000000000000))
或计算
递归(10000000000000000)
。使用对数可以验证所涉及的内存是否过大。您试图计算的函数比任何指数函数都增长得快。谢谢。我试过你的方法,但奇怪的是结果总是1。你知道为什么吗?而且这个计划永远不会结束。它不显示任何输出。@Vincent.N此答案中的代码并不总是返回1。如果这就是你所观察到的——也许检查你的缩进。它“永远”不会结束,因为循环10000000000000000次需要很多时间。在for loop中添加一个简单的打印,看看效果如何。谢谢大家的回答@约翰科勒曼:对不起,我太蠢了。我把I和1搞混了,没注意到。@RafalS我试过了