计算前1000个阶乘的累积和?

时间:2013-02-07 18:57:40

标签: python function sum

之前我曾问过类似的问题,但这种情况有所不同。以下是我的锻炼。我得到的答案与使用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()

2 个答案:

答案 0 :(得分:4)

你的阶乘函数永远不会返回任何东西。将print更改为return

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代替rangerange在内存中创建一个列表,而xrange只创建一个迭代器。

答案 1 :(得分:0)

首先,每个人都指出的主要问题是:你实际上并没有总结阶乘,甚至没有返回你可以传递给sum的值,你只是打印出阶乘。< / p>

但即使你解决了这个问题,你实际上也不会计算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)

(这需要itertools recipes中的consume功能,或者从more-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}},然后迭代地应用另一个简单转换+=以获得一个新的(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, …]