2010-07-16 31 views
8

ia giả sử có một biểu hiện nhân giống với nhiều multiplicands (biểu thức nhỏ)hiện python biểu thức nhân đánh giá nhanh hơn nếu tìm thấy một số không?

expression = a*b*c*d*....*w 

nơi ví dụ c là (x-1), d là (y ** 2-16), k là (x y-60) ..... x, y là số
và tôi biết rằng c, d, k, j có thể là không
Trình tự tôi viết biểu thức có quan trọng để đánh giá nhanh hơn không?
Tốt hơn là viết c
d k j .... * w hoặc python sẽ đánh giá tất cả các biểu thức bất kể thứ tự tôi viết?

+0

Làm thế nào để giải thích thời gian cuối cùng của Baldur? –

Trả lời

7

Python v2.6.5 không kiểm tra không giá trị.

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   

Cập nhật: Tôi đã thử nghiệm Baldur biểu 's, và Python có thể và sẽ tối ưu hóa mã có liên quan đến biểu thức không đổi. lạtest6 không được tối ưu hóa.

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   

Tóm lại, nếu biểu thức bao gồm các biến, thứ tự không quan trọng. Mọi thứ sẽ được đánh giá.

+1

Đây là hằng số, trong khi câu hỏi liên quan đến biểu thức nhân. – ShreevatsaR

+0

Điều này vẫn liên quan đến biểu thức không đổi, BTW. :-) Tôi nghĩ rằng những điều đúng để so sánh sẽ là một cái gì đó như (nói) x = 5; y = 12; (x * y-58) * (x * y-59) * (x * y-60) cho các thứ tự khác nhau của biểu thức cuối cùng (nhưng với các hằng số lớn hơn). – ShreevatsaR

+0

@ShreevatsaR, thôi nào, không phải 'a * b * c' đã chứng minh điều đó chưa? Dù sao, tôi đã kết hợp nhiều hơn. Thực sự, trừ khi tôi đang thiếu một cái gì đó, tôi không nghĩ rằng trình biên dịch sẽ nhúng mã kiểm tra các biến cho giá trị bằng không. Mã được tạo luôn là chuỗi tải, nhân, cộng, trừ các chỉ lệnh. –

-1

Có thể là không. Phép nhân là một trong những hoạt động rẻ nhất của tất cả mọi người. Nếu một 0 nên được nhanh hơn sau đó nó sẽ là cần thiết để kiểm tra số không trước và đó có thể là chậm hơn so với chỉ làm phép nhân.

Giải pháp nhanh nhất nên multiply.reduce()

+2

Bạn quên rằng ints (Python 3.X) và longs (Python 2.X) có độ dài thay đổi, và thời gian nhân tăng theo chiều dài. Vì vậy, '0 * khổng lồ * lớn 'sẽ chạy nhanh hơn rất nhiều so với' khổng lồ * lớn * 0' –

+0

Điểm tốt, tôi đã quên điều đó. – Mene

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 
>>> 
5

Đừng cố gắng để tối ưu hóa trước khi bạn chuẩn.

Với ý nghĩ đó, đúng là tất cả các biểu thức sẽ được đánh giá ngay cả khi cụm từ trung gian bằng 0.

Đơn hàng có thể vẫn còn quan trọng. Biểu thức là evaluated from left to right. Nếu a,b,c,... là số rất lớn, chúng có thể buộc Python phân bổ nhiều bộ nhớ, làm chậm quá trình tính toán trước khi nói đến j=0. (Nếu j=0 xuất hiện sớm hơn trong biểu thức, thì sản phẩm sẽ không bao giờ nhận được lớn và không cần phân bổ bộ nhớ bổ sung).

Nếu sau thời gian mã của bạn với timeit hoặc cProfile, bạn cảm thấy đây có thể là tình hình của bạn, sau đó bạn có thể thử trước khi đánh giá c,d,k,j, và thử nghiệm

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

Sau đó, lần này với timeit hoặc cProfile cũng . Cách duy nhất để thực sự biết điều này có hữu ích trong tình huống của bạn hay không là chuẩn mực.

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 

Mặc dù PyPy là nhanh hơn nhiều, nó không xuất hiện để tối ưu hóa này một trong hai:

% 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 
+0

Điều này làm cho Python có vẻ thực sự ngu ngốc. Không nên nó bắt những thứ như phép nhân bằng không trong quá trình biên dịch sang bytecode và tối ưu hóa chúng ra? PyPy có tốt hơn ở những thứ như vậy không? – endolith

+1

@endolith: Không, PyPy cũng không tối ưu hóa điều này. Xem ở trên. – unutbu

+0

Nhưng trong cả hai ví dụ của bạn, thời gian được giảm xuống theo thứ tự độ lớn khi bạn đặt 0 ngay từ đầu, phải không? Tôi đoán tôi đã bỏ lỡ một cái gì đó .. Bạn có thể vui lòng xây dựng? – George

4

Đây chỉ là kiểm tra nhanh trong Python 3.1:

>>> import timeit 
>>> timeit.timeit('243*325*(5539**35)*0') 
0.5147271156311035 
>>> timeit.timeit('0*243*325*(5539**35)') 
0.153839111328125 

và điều này bằng Python 2.6:

>>> timeit.timeit('243*325*(5539**35)*0') 
0.72972488403320312 
>>> timeit.timeit('0*243*325*(5539**35)') 
0.26213502883911133 

Vì vậy, để không tham gia vào nó.

Ngoài ra tôi nhận được kết quả này trong Python 3.1:

>>> timeit.timeit('(256**256)*0') 
0.048995018005371094 
>>> timeit.timeit('0*(256**256)') 
0.1501758098602295 

Tại sao trên trái đất?

+0

Bao nhiêu lần 'thời gian' thực thi? –

+0

nevermind ... http://docs.python.org/library/timeit.html?highlight=timeit#timeit.timeit –

+4

Kết quả thời gian cuối cùng là do khả năng giới hạn của trình tối ưu hóa lổ nhìn trộm của CPython. Bytecode cho biểu thức '(256 ** 256) * 0' được xếp tất cả các con đường xuống một hằng số' 0', do đó, thời gian của bạn không bao gồm bất kỳ phép toán số học nào cả. Đối với biểu thức thứ hai, '256 ** 256' được xếp thành một hằng số, nhưng bạn vẫn còn lại với phép nhân bằng' 0'. Tôi đoán điều này là do peepholer cơ bản hoạt động từ trái sang phải. –

Các vấn đề liên quan