Python的数学.阶乘没有记忆。在
我将引导你通过一些尝试和错误的例子,看看为什么要得到一个真正的记忆和工作的阶乘函数,你必须重新定义它考虑到一些事情。在
另一个答案实际上是不正确的。在这里import math
cache = {}
def myfact(x):
return cache.setdefault(x,math.factorial(x))
线
^{pr2}$
每次都同时计算x和{},因此性能没有提高。在
你可以考虑做这样的事情:if x not in cache:
cache[x] = math.factorial(x)
return cache[x]
但实际上这也是错误的。是的,您避免再次计算同一个x的阶乘,但请考虑,例如,如果您要计算myfact(1000),然后再计算{}。它们都是完全计算的,因此没有利用myfact(1000)自动计算myfact(999)这一事实。在
然后自然会写下这样的话:def memoize(f):
"""Returns a memoized version of f"""
memory = {}
def memoized(*args):
if args not in memory:
memory[args] = f(*args)
return memory[args]
return memoized
@memoize
def my_fact(x):
assert x >= 0
if x == 0:
return 1
return x * my_fact(x - 1)
这会奏效的。不幸的是,它很快就达到了最大递归深度。在
那么如何实施呢?在
下面是一个真正记忆化的factorial示例,它利用factorials的工作方式,并且不会使用递归调用来消耗所有堆栈:# The 'max' key stores the maximum number for which the factorial is stored.
fact_memory = {0: 1, 1: 1, 'max': 1}
def my_fact(num):
# Factorial is defined only for non-negative numbers
assert num >= 0
if num <= fact_memory['max']:
return fact_memory[num]
for x in range(fact_memory['max']+1, num+1):
fact_memory[x] = fact_memory[x-1] * x
fact_memory['max'] = num
return fact_memory[num]
我希望你觉得这个有用。在
编辑:
如前所述,实现同样优化同时又具有递归的简洁性和优雅性的方法是将函数重新定义为tail-recursive函数。在def memoize(f):
"""Returns a memoized version of f"""
memory = {}
def memoized(*args):
if args not in memory:
memory[args] = f(*args)
return memory[args]
return memoized
@memoize
def my_fact(x, fac=1):
assert x >= 0
if x < 2:
return fac
return my_fact(x-1, x*fac)
尾部递归函数实际上可以被解释器/编译器识别并自动翻译/优化为迭代版本,但并非所有的解释器/编译器都支持这一点。在
不幸的是,python不支持尾部递归优化,因此仍然可以得到:RuntimeError: maximum recursion depth exceeded
当我的事实输入很高。在