我正在尝试为超快因子函数编写代码。我已经尝试了一点,并提出了以下三个候选人(除了math.factorial):
def f1():
return reduce(lambda x,y : x * y, xrange(1,31))
def f2():
result = 1
result *= 2
result *= 3
result *= 4
result *= 5
result *= 6
result *= 7
result *= 8
#and so-on...
result *= 28
result *= 29
result *= 30
return result
def f3():
return 1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20*21*22*23*24*25*26*27*28*29*30
我已经计时了这些功能。结果如下:
In [109]: timeit f1()
100000 loops, best of 3: 11.9 µs per loop
In [110]: timeit f2()
100000 loops, best of 3: 5.05 µs per loop
In [111]: timeit f3()
10000000 loops, best of 3: 143 ns per loop
In [112]: timeit math.factorial(30)
1000000 loops, best of 3: 2.11 µs per loop
显然,f3()取得了成功。我试过实现这个。为了详细,我尝试编写生成如下字符串的代码:
“1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 ........”然后使用eval来评估此字符串。 (承认'eval'是邪恶的)。然而,这种方法在时间上没有给我带来任何好处。事实上,我花了将近150微秒才完成。
请告知如何概括f3()。
答案 0 :(得分:4)
f3
只是快速,因为它在调用它时实际上并没有计算任何东西。整个计算在编译时进行优化,并替换为最终值,因此所有时间都是函数调用开销。
如果我们使用dis
模块反汇编函数,这一点尤其明显:
>>> import dis
>>> dis.dis(f3)
2 0 LOAD_CONST 59 (265252859812191058636308480000000L)
3 RETURN_VALUE
不可能将此加速概括为一个接受参数并返回其阶乘的函数。
答案 1 :(得分:1)
f3()取得了进展,因为当函数被定义时,Python只是将乘法字符串优化到最终结果,并且f3()的有效定义变为:
def f3():
return 8222838654177922817725562880000000
,因为调用函数时不需要计算,运行得非常快!
产生在数字列表之间放置*运算符的所有效果的一种方法是使用reduce
模块中的functools
。这有点像你正在寻找的吗?
from functools import reduce
def fact(x):
return reduce((lambda x, y: x * y), range(1, x+1))
答案 2 :(得分:0)
我认为这些都不是很好的因子函数,因为没有一个参数给函数。最后一个运行良好的原因是因为它最小化了解释器步骤的数量,但这仍然不是一个好的答案:所有这些都具有相同的复杂性(与值的大小成线性关系)。我们可以做得更好:O(1)。
import math
def factorial(x):
return math.gamma(x+1)
这会随着输入值不断扩大,牺牲一些精度。当性能很重要时,情况仍然会更好。
我们可以做一个快速的基准测试:
import math
def factorial_gamma(x):
return math.gamma(x+1)
def factorial_linear(x):
if x == 0 or x == 1:
return 1
return x * factorial_linear(x-1)
In [10]: factorial_linear(50)
Out[10]: 30414093201713378043612608166064768844377641568960512000000000000
In [11]: factorial_gamma(50)
Out[11]: 3.0414093201713376e+64
In [12]: %timeit factorial_gamma(50)
537 ns ± 6.84 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [13]: %timeit factorial_linear(50)
17.2 µs ± 120 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
因子50的增加30倍。不错。
https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.misc.factorial.html
答案 3 :(得分:0)
正如其他人所说,f3()
实际上并没有计算任何可以获得如此快速结果的原因。通过将其赋予功能,您无法实现同样的目标。
你也许想知道为什么math.factorial()
如此之快,因为
math module's functions在C:
此模块始终可用。它提供对C标准
定义的数学函数的访问
通过在C中使用高效算法,您可以获得如此快速的结果。
这里你最好的选择是使用以下功能,但如果你纯粹需要性能
,那么我更喜欢使用math.factorial
def f3(x):
ans=1
for i in range(1,x+1):
ans=ans*i
return ans
print(f3(30))