之前我曾问过类似的问题,但这种情况有所不同。以下是我的锻炼。我得到的答案与使用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()
答案 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
代替range
。 range
在内存中创建一个列表,而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, …]
。