Lý do (hơi bất ngờ) cho kết quả của bạn là Python có vẻ gấp các biểu thức liên tục liên quan đến phép nhân dấu chấm động và lũy thừa, nhưng không phân chia. math.sqrt()
là một con thú khác hoàn toàn vì không có bytecode cho nó và nó liên quan đến một cuộc gọi chức năng.
Mở Python 2.6.5, đoạn code sau:
x1 = 1234567890.0/4.0
x2 = 1234567890.0 * 0.25
x3 = 1234567890.0 ** 0.5
x4 = math.sqrt(1234567890.0)
biên dịch với bytecode sau:
# x1 = 1234567890.0/4.0
4 0 LOAD_CONST 1 (1234567890.0)
3 LOAD_CONST 2 (4.0)
6 BINARY_DIVIDE
7 STORE_FAST 0 (x1)
# x2 = 1234567890.0 * 0.25
5 10 LOAD_CONST 5 (308641972.5)
13 STORE_FAST 1 (x2)
# x3 = 1234567890.0 ** 0.5
6 16 LOAD_CONST 6 (35136.418286444619)
19 STORE_FAST 2 (x3)
# x4 = math.sqrt(1234567890.0)
7 22 LOAD_GLOBAL 0 (math)
25 LOAD_ATTR 1 (sqrt)
28 LOAD_CONST 1 (1234567890.0)
31 CALL_FUNCTION 1
34 STORE_FAST 3 (x4)
Như bạn có thể thấy, nhân và lũy thừa mất không có thời gian ở tất cả vì họ thực hiện lại khi mã được biên dịch. Phân chia mất nhiều thời gian hơn vì nó xảy ra trong thời gian chạy. Quảng trường gốc không chỉ là hoạt động tốn kém nhất về tính toán của bốn, nó cũng phát sinh các chi phí khác nhau mà những người khác không (tra cứu thuộc tính, gọi hàm vv).
Nếu bạn loại bỏ ảnh hưởng của gấp liên tục, có rất ít để tách nhân và chia:
In [16]: x = 1234567890.0
In [17]: %timeit x/4.0
10000000 loops, best of 3: 87.8 ns per loop
In [18]: %timeit x * 0.25
10000000 loops, best of 3: 91.6 ns per loop
math.sqrt(x)
thực sự là nhanh hơn một chút so với x ** 0.5
, có lẽ vì đây là một trường hợp đặc biệt của thứ hai và có thể do đó được thực hiện một cách hiệu quả hơn, mặc dù chi phí chung:
In [19]: %timeit x ** 0.5
1000000 loops, best of 3: 211 ns per loop
In [20]: %timeit math.sqrt(x)
10000000 loops, best of 3: 181 ns per loop
chỉnh sửa 2011/11/16: liên tục biểu hiện gấp được thực hiện bởi pe Python bộ tối ưu hóa ephole. Các mã nguồn (peephole.c
) chứa các bình luận sau giải thích lý do tại sao bộ phận liên tục không gấp:
case BINARY_DIVIDE:
/* Cannot fold this operation statically since
the result can depend on the run-time presence
of the -Qnew flag */
return 0;
Cờ -Qnew
phép "phân chia đúng" quy định tại PEP 238.
Câu trả lời bạn đã chấp nhận cho câu hỏi của mình (mà tôi cho rằng câu trả lời cho câu hỏi thực sự của bạn) không liên quan nhiều đến tiêu đề câu hỏi của bạn. Bạn có thể chỉnh sửa nó để có một cái gì đó để làm với gấp liên tục? –
@ZanLynx - Xin chào. Bạn có muốn làm rõ không? Tôi thấy rằng tiêu đề câu hỏi thể hiện chính xác những gì tôi muốn biết (tại sao X nhanh hơn Y) và câu trả lời tôi chọn chính xác ... Có vẻ như một trận đấu hoàn hảo với tôi ... nhưng có lẽ tôi đang nhìn cái gì đó? – mac
Phép nhân và chức năng nguồn luôn nhanh hơn các phép chia và sqrt() vì bản chất của chúng. Các hoạt động của bộ phận và gốc thường phải sử dụng một loạt các phép tính gần đúng hơn và tốt hơn và không thể đi trực tiếp đến câu trả lời đúng như phép nhân có thể. –