しばらくの間、MATLAB スクリプトを作成していますが、「フードの下で」どのように機能するのかまだわかりません。次のスクリプトを考えてみましょう。これは、3 つの異なる方法で (大きな) ベクトルを使用して計算を行います。
- MATLAB ベクトル演算。
- コンポーネントごとに同じ計算を行うサイクルの場合は単純です。
- 一部の割り当てと一部の割り当てを回避するため、2.よりも高速であると想定される最適化されたサイクル。
コードは次のとおりです。
N = 10000000;
A = linspace(0,100,N);
B = linspace(-100,100,N);
C = linspace(0,200,N);
D = linspace(100,200,N);
% 1. MATLAB Operations
tic
C_ = C./A;
D_ = D./B;
G_ = (A+B)/2;
H_ = (C_+D_)/2;
I_ = (C_.^2+D_.^2)/2;
X = G_ .* H_;
Y = G_ .* H_.^2 + I_;
toc
tic
X;
Y;
toc
% 2. Simple cycle
tic
C_ = zeros(1,N);
D_ = zeros(1,N);
G_ = zeros(1,N);
H_ = zeros(1,N);
I_ = zeros(1,N);
X = zeros(1,N);
Y = zeros(1,N);
for i = 1:N,
C_(i) = C(i)/A(i);
D_(i) = D(i)/B(i);
G_(i) = (A(i)+B(i))/2;
H_(i) = (C_(i)+D_(i))/2;
I_(i) = (C_(i)^2+D_(i)^2)/2;
X(i) = G_(i) * H_(i);
Y(i) = G_(i) * H_(i)^2 + I_(i);
end
toc
tic
X;
Y;
toc
% 3. Opzimized cycle
tic
X = zeros(1,N);
Y = zeros(1,N);
for i = 1:N,
X(i) = (A(i)+B(i))/2 * (( C(i)/A(i) + D(i)/B(i) ) /2);
Y(i) = (A(i)+B(i))/2 * (( C(i)/A(i) + D(i)/B(i) ) /2)^2 + ( (C(i)/A(i))^2 + (D(i)/B(i))^2 ) / 2;
end
toc
tic
X;
Y;
toc
MATLAB は行列/ベクトル上に構築されているため、常に計算をベクトル化しようとする必要があることを知っているため (したがって、最近では、常に最適な選択とは限りません)、次のようなことを期待しています。
C = A .* B;
よりも高速です:
for i in 1:N,
C(i) = A(i) * B(i);
end
私が期待していないのは、私が使用している 2 番目と 3 番目の方法は 1 サイクルしか実行しないにもかかわらず、上記のスクリプトでも実際には高速であることです。一方、最初の方法は多くのベクトル操作を実行します (理論的には、「 " 毎回サイクル)。これにより、MATLAB には(たとえば) 次のことを可能にする魔法があると結論付けざるを得ません。
C = A .* B;
D = C .* C;
内部にいくつかの操作がある単一の「for」サイクルよりも高速に実行されます。
そう:
- 最初の部分が速く実行されないようにする魔法は何ですか?
- "D= A .* B" と書くと、MATLAB は実際に "for" サイクルを使用してコンポーネント単位の計算を実行しますか、それとも D に "bla" と "bla" の乗算が含まれていることを単に追跡しますか?
編集
- C++ を使用して (おそらくいくつかのライブラリを使用して) 同じ計算を実装したいとします。MATLAB の最初のメソッドは、C++ で実装された 3 つ目のメソッドよりも高速ですか? (この質問には自分で答えます。少し時間をください。)
編集2
リクエストに応じて、ここに実験ランタイムがあります。
パート 1: 0.237143
パート 2: 4.440132 のうち 0.195154 を割り当て
パート 3: 2.280640 のうち 0.057500 を割り当て
そしてJITなし:
パート 1: 0.337259
パート 2: 149.602017 のうち 0.033886 を割り当て
パート 3: 82.167713 のうち 0.010852 を割り当て