假设我有一个带有许多被乘数(小表达式)的乘法表达式
expression = a*b*c*d*....*w
其中例如c是(x-1),d是(y ** 2-16),k是(x y-60)..... x,y是数字
我知道c,d,k,j可能为零
我写这个表达式的顺序是否对于更快的评估很重要?
写c d k j是不是更好.... * w或python会评估所有表达式,无论我写的顺序是什么?
答案 0 :(得分:7)
Python v2.6.5不会检查零值。
def foo():
a = 1
b = 2
c = 0
return a * b * c
>>> import dis
>>> dis.dis(foo)
2 0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (a)
3 6 LOAD_CONST 2 (2)
9 STORE_FAST 1 (b)
4 12 LOAD_CONST 3 (3)
15 STORE_FAST 2 (c)
5 18 LOAD_FAST 0 (a)
21 LOAD_FAST 1 (b)
24 BINARY_MULTIPLY
25 LOAD_FAST 2 (c)
28 BINARY_MULTIPLY
29 RETURN_VALUE
更新:我测试了Baldur的表达式,Python可以并且将优化涉及常量表达式的代码。 怪异的是test6
没有优化。
def test1():
return 0 * 1
def test2():
a = 1
return 0 * a * 1
def test3():
return 243*(5539**35)*0
def test4():
return 0*243*(5539**35)
def test5():
return (256**256)*0
def test6():
return 0*(256**256)
>>> dis.dis(test1) # 0 * 1
2 0 LOAD_CONST 3 (0)
3 RETURN_VALUE
>>> dis.dis(test2) # 0 * a * 1
5 0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (a)
6 6 LOAD_CONST 2 (0)
9 LOAD_FAST 0 (a)
12 BINARY_MULTIPLY
13 LOAD_CONST 1 (1)
16 BINARY_MULTIPLY
17 RETURN_VALUE
>>> dis.dis(test3) # 243*(5539**35)*0
9 0 LOAD_CONST 1 (243)
3 LOAD_CONST 5 (104736434394484...681759461305771899L)
6 BINARY_MULTIPLY
7 LOAD_CONST 4 (0)
10 BINARY_MULTIPLY
11 RETURN_VALUE
>>> dis.dis(test4) # 0*243*(5539**35)
12 0 LOAD_CONST 5 (0)
3 LOAD_CONST 6 (104736433252667...001759461305771899L)
6 BINARY_MULTIPLY
7 RETURN_VALUE
>>> dis.dis(test5) # (256**256)*0
15 0 LOAD_CONST 4 (0L)
3 RETURN_VALUE
>>> dis.dis(test6) # 0*(256**256)
18 0 LOAD_CONST 1 (0)
3 LOAD_CONST 3 (323170060713110...853611059596230656L)
6 BINARY_MULTIPLY
7 RETURN_VALUE
简而言之,如果表达式包含变量,则顺序无关紧要。一切都将被评估。
答案 1 :(得分:5)
在基准测试之前不要尝试优化。
考虑到这一点,即使中间项为零,也会评估所有表达式。
订单可能仍然重要。表达式为evaluated from left to right。如果a,b,c,...
是非常大的数字,它们可能会迫使Python分配大量内存,从而在j=0
之前减慢计算速度。 (如果j=0
在表达式中较早出现,那么产品将永远不会变得那么大,并且不需要额外的内存分配。)
如果在使用timeit或cProfile计算代码后,您认为这可能是您的情况,那么您可以尝试预先评估c,d,k,j
,然后测试
if not all (c,d,k,j):
expression = 0
else:
expression = a*b*c*d*....*w
然后使用timeit
或cProfile
计算时间。真正判断这在你的情况下是否有用的唯一方法是进行基准测试。
In [333]: import timeit
In [334]: timeit.timeit('10**100*10**100*0')
Out[334]: 1.2021231651306152
In [335]: timeit.timeit('0*10**100*10**100')
Out[335]: 0.13552498817443848
虽然PyPy要快得多,但它似乎也没有对此进行优化:
% pypy-c
Python 2.7.3 (d994777be5ab, Oct 12 2013, 14:13:59)
[PyPy 2.2.0-alpha0 with GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``http://twitpic.com/52ae8f''
>>>> import timeit
>>>> timeit.timeit('10**100*10**100*0')
0.020643949508666992
>>>> timeit.timeit('0*10**100*10**100')
0.003732919692993164
答案 2 :(得分:4)
这只是Python 3.1中的快速检查:
>>> import timeit
>>> timeit.timeit('243*325*(5539**35)*0')
0.5147271156311035
>>> timeit.timeit('0*243*325*(5539**35)')
0.153839111328125
,这在Python 2.6中:
>>> timeit.timeit('243*325*(5539**35)*0')
0.72972488403320312
>>> timeit.timeit('0*243*325*(5539**35)')
0.26213502883911133
所以订单确实进入了它。
我也在Python 3.1中得到了这个结果:
>>> timeit.timeit('(256**256)*0')
0.048995018005371094
>>> timeit.timeit('0*(256**256)')
0.1501758098602295
为什么在地球上?
答案 3 :(得分:2)
>>> import timeit
>>> timeit.timeit('1*2*3*4*5*6*7*8*9*9'*6)
0.13404703140258789
>>> timeit.timeit('1*2*3*4*5*6*7*8*9*0'*6)
0.13294696807861328
>>>
答案 4 :(得分:-1)
可能不是。乘法是最便宜的操作之一。如果0应该更快,那么有必要在之前检查零,这可能比仅进行乘法更慢。
最快的解决方案应该是multiply.reduce()