如果在Python中找到零,乘法表达式会更快吗?

9 投票
5 回答
1899 浏览
提问于 2025-04-16 01:23

假设我有一个乘法表达式,里面有很多小的乘数(小表达式)

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会不管我写的顺序,都会计算所有的表达式呢?

5 个回答

5

在你进行优化之前,先进行基准测试是很重要的。

记住这一点,即使中间的某个值是零,所有的表达式仍然会被计算。

顺序可能还是很重要的。表达式是从左到右计算的。如果 a,b,c,... 是非常大的数字,它们可能会让Python分配很多内存,这样在计算到 j=0 之前就会变得很慢。(如果 j=0 在表达式中出现得更早,那么乘积就不会变得那么大,也就不需要额外的内存分配了)。

如果你用 timeitcProfile 测试了你的代码后,觉得可能会遇到这种情况,那么你可以尝试先计算 c,d,k,j 的值,然后再进行测试。

if not all (c,d,k,j):
    expression = 0
else:
    expression = a*b*c*d*....*w

然后也用 timeitcProfile 来测量这个结果。判断这个方法在你情况中是否有用,唯一的方法就是进行基准测试。

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
5

这是在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

这到底是为什么呢?

7

Python 2.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        

简单来说,如果表达式里有变量,那么顺序就不重要了。所有的内容都会被计算。

撰写回答