1

我之前也问过类似的问题,但这有点不同。以下是我的锻炼。我得到的答案与我使用 python 的内置函数得到的答案不符。请指教我做错了什么,我相信内置函数的答案必须是正确的。

我的锻炼:

def fact_cum(n):
    f = 1
    for x in range(1, n +1):
        f *= x
    print f

fact_cum(1000) 

Python的内置函数:

import math
def cumFact(): 
    x = sum(math.factorial(f) for f in range(1000))
    print x

cumFact()
4

2 回答 2

4

您的阶乘函数永远不会返回任何内容。将其更改printreturn

def fact(n):
    f = 1

    for x in range(1, n +1):
        f *= x

    return f

现在你可以总结一下:

sum(fact(n) for n in range(1, 1000 + 1))

由于您使用的是 Python 2,因此请使用xrange而不是range. range在内存中创建一个列表,而xrange只是创建一个迭代器。

于 2013-02-07T19:02:07.147 回答
0

首先,每个人都指出了一个主要问题:您实际上并没有对阶乘求和,甚至没有返回可以传递给的值,sum您只是打印出阶乘。

但即使你解决了这个问题,你实际上也不会计算sum(math.factorial(i) for i in range(1000)),而是sum(math.factorial(i) for i in range(1, 1001))。如果你想要前者,你需要从 0! 开始,而不是 1!。

正如 mgilson 指出的那样,您不需要对每个阶乘重新开始。进行累积阶乘的全部意义在于您可以同步累积阶乘和总和,因此您只需要生成每个阶乘一次:

import itertools

def factorials():
    fact = 1
    for i in itertools.count(1):
        yield fact
        fact *= i

def cum_factorials():
    cum = 0
    for fact in factorials():
        cum += fact
        yield cum

def cum_factorial(n):
    cf = cum_factorials()
    consume(cf, 1000)
    return next(cf)

(这需要来自recipesconsume的函数,或者从…导入的函数,或者应该很明显如何自己编写它。)itertoolsmore-itertools


显然,您不需要通过生成无限的累积阶乘列表并选择第 n 个来做到这一点,但这会阻止 Haskell 程序员嘲笑您选择的语言,这不是真正重要的吗?

更严重的是,想象一下你将如何在纸上做到这一点。首先,你要写下一个阶乘列表:

1
1 * 1 = 1
1 * 2 = 2
2 * 3 = 6
6 * 4 = 24
...

然后,您将在旁边写另一列,总结到目前为止的阶乘。

1             1
1 * 1 = 1     1 + 1 = 2
1 * 2 = 2     2 + 2 = 4
2 * 3 = 6     4 + 6 = 10
6 * 4 = 24    10 + 24 = 34
24 * 5 = 120  34 + 120 = 154
...           ...

那么,你如何在 Python 中做同样的事情呢?

好吧,一种选择是将算法重组为可以按顺序编写的内容,如下所示:

def cum_fact(n):
    cumulative_sum = 1
    latest_factorial = 1
    for i in range(1, n):
        latest_factorial *= i
        cumulative_sum += latest_factorial
    return cumulative_sum

但这实际上比你在纸上做的更难理解,也更容易出错。

另一种方法是弄清楚如何让 Python 完成你在纸上所做的事情:取一个无限序列(1, 2, 3, 4, …),对那个序列迭代地应用一个简单的变换*=来得到一个新的序列(1, 1, 2, 6, 24, …),然后对那个序列迭代地应用另一个简单的变换+=来得到一个新的序列(1, 2, 4, 10, 34, …). 然后,您只需要该序列中的第 1001 个值,所以……扔掉前 1000 个并取下一个。

itertools.count(1)给你第一个序列(1, 2, 3, …)。你可以这样写:

def count(n):
    while True:
        yield n
        n += 1

那是一个生成器函数。我不认为我可以在一段中解释整个概念,但这是基本思想:它不是返回一个值,而是产生一个值序列。每次点击yield,调用者都会得到一个值。每次你要求下一个值时,它都会从它剩下的地方拾起,直到下一个yield。如果您在交互式解释器中使用这个想法一段时间,也许它会立即到位 - 但是,更好的是,您可能想在谷歌上搜索教程。

接下来,虽然您可以使用折叠函数应用每个转换,但这可能有点太高级了,无法考虑,所以我使用另外两个生成器函数明确地写出来。

最后,它consume本身有点不同——它不是一个生成器,而是一个接受和修改迭代器的函数,如下所示:

def consume(iter, n):
    for i in range(n):
        next(iter)

所以,如果有[1, 2, 3, 4, 5, 6, …],而你consume是前 3 个元素,你会得到[4, 5, 6, …].

于 2013-02-07T19:24:27.443 回答