Python:math.factorial是memoized吗?

时间:2011-02-12 06:47:34

标签: python algorithm caching

我用三种不同的方式解决problem,其中两种是递归的,我自己也记住它们。另一个不是递归的,而是使用math.factorial。我需要知道是否需要为其添加显式的memoization。

感谢。

4 个答案:

答案 0 :(得分:4)

在此链接上搜索math_factorial,您将在python中找到它的实现:

http://svn.python.org/view/python/trunk/Modules/mathmodule.c?view=markup

P.S。这是为python2.6

答案 1 :(得分:4)

Python的math.factorial不是memoized,它是一个简单的for循环,将值从1乘以你的arg。如果需要记忆,则需要明确地进行记忆。

这是一种使用字典setdefault方法进行memoize的简单方法。

import math
cache = {}
def myfact(x):
    return cache.setdefault(x,math.factorial(x))
print myfact(10000)
print myfact(10000)

答案 2 :(得分:2)

Python的math.factorial没有被记忆。

我将引导您完成一些试验和错误示例,了解为什么要获得一个真正的记忆和工作因子功能,您必须从头开始重新定义它,并考虑到几个方面。

另一个答案实际上是不正确的。这里,

import math
cache = {}
def myfact(x):
    return cache.setdefault(x,math.factorial(x))

return cache.setdefault(x,math.factorial(x))

每次都会计算xmath.factorial(x),因此您的性能不会提高。

您可能会想到这样的事情:

if x not in cache:
    cache[x] = math.factorial(x)
return cache[x]

但实际上这也是错误的。是的,您可以避免重新计算相同x的阶乘,但请考虑一下,例如,如果您要计算myfact(1000)并且很快就会计算myfact(999)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) 这一事实并没有带来任何好处。

然后写这样的东西很自然:

# 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]

这将起作用。不幸的是,它很快就达到了最大递归深度。

那么如何实现呢?

这是一个真正的memoized阶乘的例子,它利用了阶乘的工作方式,并且不会使用递归调用来消耗所有堆栈:

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)

我希望你觉得这很有用。

修改

正如笔记一样,实现同样优化的一种方法同时具有递归的简洁性和优雅性,将该函数重新定义为tail-recursive函数。

RuntimeError: maximum recursion depth exceeded

尾部递归函数实际上可以被解释器/编译器识别并自动转换/优化为迭代版本,但并非所有解释器/编译器都支持此功能。

不幸的是,python不支持尾递归优化,所以你仍然得到:

{{1}}

当my_fact的输入为高时。

答案 3 :(得分:1)

我迟到了,但这里是我在Python中实现高效的memoized factorial函数的2c。这种方法更有效,因为它依赖于类似数组的结构(即list)而不是散列容器(即dict)。不涉及递归(免除一些Python函数调用开销)并且没有涉及缓慢的for循环。并且它(可以说)在功能上是纯粹的,因为没有涉及外部副作用(即它不修改全局变量)。它会缓存所有中间因子,因此如果您已经计算了factorial(n),那么任何0 <= m <= n和O(mn)都需要O(1)来计算factorial(m)对于任何m> ñ。

def inner_func(f):
    return f()


@inner_func
def factorial():
    factorials = [1]

    def calculate_factorial(n):
        assert n >= 0
        return reduce(lambda cache, num: (cache.append(cache[-1] * num) or cache),
                      xrange(len(factorials), n+1), factorials)[n]

    return calculate_factorial