Dường như Mathworks có các ô vuông đặc biệt trong chức năng nguồn của nó (thật không may, đó là tất cả các nguồn đóng được xây dựng mà chúng ta không thể nhìn thấy). Trong thử nghiệm của tôi trên R2013b, có vẻ như .^
, power
và realpow
sử dụng cùng một thuật toán. Đối với các ô vuông, tôi tin rằng chúng có đặc biệt là x.*x
.
1.0x (4.4ms): @()x.^2
1.0x (4.4ms): @()power(x,2)
1.0x (4.5ms): @()x.*x
1.0x (4.5ms): @()realpow(x,2)
6.1x (27.1ms): @()exp(2*log(x))
Đối với hình khối, câu chuyện khác. Chúng không còn được bao bọc đặc biệt nữa. Một lần nữa, .^
, power
, và realpow
tất cả đều giống nhau, nhưng chậm hơn thời gian này:
1.0x (4.5ms): @()x.*x.*x
1.0x (4.6ms): @()x.*x.^2
5.9x (26.9ms): @()exp(3*log(x))
13.8x (62.3ms): @()power(x,3)
14.0x (63.2ms): @()x.^3
14.1x (63.7ms): @()realpow(x,3)
Hãy nhảy lên với sức mạnh 16 để xem cách các thuật toán quy mô:
1.0x (8.1ms): @()x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x
2.2x (17.4ms): @()x.^2.^2.^2.^2
3.5x (27.9ms): @()exp(16*log(x))
7.9x (63.8ms): @()power(x,16)
7.9x (63.9ms): @()realpow(x,16)
8.3x (66.9ms): @()x.^16
Vì vậy: .^
, power
và realpow
tất cả chạy trong một thời gian liên tục liên quan đến số mũ, trừ khi nó được đặc biệt cased (-1 cũng dường như đã được đặc biệt cased). Sử dụng thủ thuật exp(n*log(x))
cũng là thời gian liên tục liên quan đến số mũ và nhanh hơn. Kết quả duy nhất tôi không hoàn toàn hiểu tại sao bình phương lặp đi lặp lại là chậm hơn so với phép nhân.
Như dự kiến, tăng kích thước x
với hệ số là 100 sẽ tăng thời gian tương tự cho tất cả các thuật toán.
Vì vậy, đạo đức của câu chuyện? Khi sử dụng số nguyên nguyên vô hướng, luôn tự làm phép nhân. Có rất nhiều thông minh trong số power
và bạn bè (số mũ có thể là dấu phẩy động, vectơ, v.v.). Ngoại lệ duy nhất là nơi Mathworks đã thực hiện tối ưu hóa cho bạn. Trong năm 2013b, có vẻ như là x^2
và x^(-1)
. Hy vọng rằng họ sẽ thêm nhiều thời gian hơn. Tuy nhiên, nói chung, lũy thừa là khó và nhân rất dễ dàng. Trong mã hiệu suất nhạy cảm, tôi không nghĩ rằng bạn có thể đi sai bằng cách luôn gõ x.*x.*x.*x
. (Tất nhiên, trong trường hợp của bạn, hãy làm theo lời khuyên của Luis` và tận dụng các kết quả trung gian trong mỗi học kỳ!)
function powerTest(x)
f{1} = @() x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x;
f{2} = @() x.^2.^2.^2.^2;
f{3} = @() exp(16.*log(x));
f{4} = @() x.^16;
f{5} = @() power(x,16);
f{6} = @() realpow(x,16);
for i = 1:length(f)
t(i) = timeit(f{i});
end
[t,idxs] = sort(t);
fcns = f(idxs);
for i = 1:length(fcns)
fprintf('%.1fx (%.1fms):\t%s\n',t(i)/t(1),t(i)*1e3,func2str(fcns{i}));
end
Tối ưu hóa có thể được thực hiện trên 'x. * X. * X. * X' kỳ lạ. Tôi đã thử 'x. *. X. * .... * X' với số lượng khác nhau của" x "từ 2 đến 8, và thời gian là tăng hoặc ít tuyến tính. Tôi đã mong đợi những va chạm; ví dụ "8" trường hợp (=> 'x.^2.^2.^2': ba hoạt động điện) nên mất ít thời gian hơn" 7 "(=> nhiều hoạt động điện) –
@LuisMendo Tôi không biết làm thế nào để xác minh, nhưng tôi có thể tưởng tượng rằng nó chỉ thực hiện 1 bước (không tối ưu lồng nhau). Đối với 7 nó sau đó sẽ giảm xuống một cái gì đó như: 'x.^2 * x.^2 * x.^2. * x' mà sẽ không chậm hơn' x.^2 * x.^2 * x.^2 . * x.^2' cho 8. Nếu làm 8 nhanh hơn làm 7 theo cách này, Mathworks có lẽ sẽ ngụ ý loại tối ưu hóa này trong chức năng nguồn. –
Có, đó có thể là lời giải thích: không làm tổ nào –