
大きなプログラムを書く際、プログラムの見通しが良くなり、後から修正しやすくするため、
同じ計算が複数回出る際には関数を多用したものを作成してきました。
ところが、プログラムの計算速度を上げたいと思い、計算時間を比較してみたところ、
関数を使わない方が圧倒的に速くなることが分かりました。
Matlabを使って、
for j = 1:100000
for i = 1:1000
y = i*i * j *j;
end
end
の計算を行った際の計算時間と、ループ内の計算を関数で置き換えた
for j = 1:100000
for i = 1:1000
y = zikan_sokutei_function ( i, j );
end
end
function [ kei ] = zikan_sokutei_function ( i, j )
kei = i * i * j * j;
end
の計算を行った時間は、
それぞれ、0.5秒と1分7.3秒、という結果になりました。
つまり関数で置き換えたことで、計算時間が実に135倍も増大したということです。
上記と同じプログラムを使ってVBAで比較したところ、
それぞれ、8.29秒と20.70秒、という結果になりました。
つまり関数で置き換えたことで、計算時間が2.5倍も増大したということです。
また、関数を使わない場合には、Matlabが最速で、関数を使う場合にはVBAが最速であるという結果になっています。
これは関数を全く使わない方が、圧倒的に高速に計算を実行できるという結果になっていますが、
こういうものなのでしょうか?
2倍程度なら許容範囲ですが、100倍以上も遅くなるのであれば、
関数は全く使うべきではない、ということになりますが、なぜこれほどまでに時間がかかるのでしょうか?
Matlabの方がVBAよりも数値計算に適しているため、VBAよりも実行速度は速くなるべきだと思いますが
関数を使った場合には、これが逆転してしまうという、かなり腑に落ちない結果となりましたが、
こういうものなのでしょうか?
No.8ベストアンサー
- 回答日時:
とにかく、matlabでの、唯一絶対の基本原則は、「for文を回しては絶対に駄目」です。
matlabで、ループ回数がものすごく多いfor文を書くと、処理時間が、行列演算の100倍どころか1000倍遅いとか平気でなります。
例えば、for文を使ったプログラムが
y=0;
for j = 1:100000
for i = 1:1000
y = y + i*i * j *j;
end
end
だとしたら、
(質問文のプログラムは、結果として何も計算していないの、少し変えました。)
matlabでは、
y = sum((1:1000).^2)*sum((1:100000).^2);
という行列演算として一行で記述してください。
同じ結果が、おそらく一瞬で出てくるはずです。
matlabの最適化機能はあまり頭が良くないので、かなり単純な構造じゃないと、ループを行列演算に自動変換してくれません。
なんで、基本的には、ユーザーが上記のように、明示的にきちんとループではなくて行列演算の形で記述する必要があります。
No.7
- 回答日時:
#4です。
ちょっと、きちんと言いたいことの本質が伝わらないかもと思ったので補足。
matlabに関して言えば、100倍遅くなった原因は、
・関数呼び出しにしたから
ではなくて、
・ループ(for文)を使ったから
です。
一見、両方とも、ループが存在しているように見えますが、関数版でないほうは、matlabが内部でプログラムを自動的に解析して、内部で、ループではなくて行列計算になるように変更して実行されたため速いのです。
関数版のほうは、最適化が利かなくなってしまったため、実際にループとして実行されたので、劇遅になってしまったわけです。
>2倍程度なら許容範囲ですが、100倍以上も遅くなるのであれば、
>関数は全く使うべきではない、ということになりますが、なぜこれほどまでに時間がかかるのでしょうか?
matlabに関して言えば、関数呼び出し自体は当然使用してもよいですが、大規模なループ(for文)は使用すべきではありません。(それこそ100倍遅くなります)
皆さんご回答ありがとうございます。
遅くなる原因は理解することができました。
もう一つ関連した質問をお聞きしたいのですが、
関数に変数のやり取りをしているために遅くなる、というのであれば、
グローバル変数を使ってやれば、引数のやり取りだけはなくなり、その分速くなるのではないかと思い
試してみました。
計算回数を一桁下げて
for j = 1:10000
for i = 1:1000
とした上で、
VBAで
public i, j
をsubの前に書いて実行すると、
iとjをグローバル変数としていない場合で、2.00秒、した場合で1.72秒となり、
若干だけですが、速度が向上しました。
一方で、matlabで
global i j;
を定義してから同じことをやってみると、
iとjをグローバル変数としていない場合で、6.5秒、した場合で2分12.2秒となり、
なぜかVBAとは反対に、20倍も遅くなってしまうという結果になりました。
この結果は、No.7さんが仰るようにforループを行列としてmatlabが最適化したと考えたとしても、
関数と変数のやり取りをしているためであると、考えたとしても説明がつきません。
なぜmatlabではこのようにグローバル変数を用いた方が20倍も計算速度が遅くなるのでしょうか?
No.6
- 回答日時:
> 2倍程度なら許容範囲ですが、100倍以上も遅くなるのであれば、
> 関数は全く使うべきではない、ということになりますが、...
それは極論ですね。速度のボトルネックの多くはプログラムのごく一部です。速度のチューニングは後回しにして、関数を多用する質問者さんの従来のスタイルが正しいと思います。
逆に関数を使わないと、アルゴリズムのボトルネックを探すことが難しくなるでしょう。プロファイラ等で時間計測することが難しくなってしまうので。
しかし最適化すべき部分と期限が決まったなら、どんな手段もためらうべきではないとは思います。
No.5
- 回答日時:
お疲れ様です。
抽象的な説明ですが参考に為れば幸いです。
例えば次のような関数が有ったとします。
add_abc = abc( a, b, c )
function abc( a, b, c ){
return( a + b + c )
}
これを呼び出す一連の処理は
(注:値の受け渡しにstackを利用する前提です)
1.呼び出し元で、aの値をstackに格納
2.呼び出し元で、bの値をstackに格納
3.呼び出し元で、cの値をstackに格納
4.呼び出し元で、abcを呼び出す
5.関数側で、aの値を取り出す
6.関数側で、bの値を取り出す
7.関数側で、cの値を取り出す
8.関数側で、演算 a + b + c を行う
9.関数側で、結果(return値)を汎用レジスタなどに置く
10.関数側で、return命令で呼び出し元に帰る
11.呼び出し元で、cの値をstackから削除
12.呼び出し元で、bの値をstackから削除
13.呼び出し元で、aの値をstackから削除
14.呼び出し元で、結果(return値)をadd_abc変数に格納する
、を行っています。
1~7、9~13までが呼び出しに伴うオーバーヘッドとなります。
8と14は関数を使わなければそのまま行っている事ですよね。
簡単な演算なのでオーバーヘッドが物凄く多く感じますが
処理内容によっては無視できる範囲になります。
今回のように呼び出し回数が多い場合にはオーバーヘッドばかり増えますよね。
そこのところを考えて判断してください。
No.4
- 回答日時:
どう書くのが速いか、言語と、コンパイラやインタプリタの最適化機能によるので一般論では言えません。
通常は、まったく同じ内容を関数化すれば、最適化が効き難くなる分だけ遅くなることが多いとは思いますが、場合によっては、関数化することで、コンパイラの中での最適化用で考えないと行けないスコープが狭まることで、逆に最適化が効きやすくなって高速化する場合もあります。
その上で、Matlabに限定した話ですが。
まず、Matlabでは、基本的に、for文などのループは劇遅なので使ってはいけません。
ループで行列の要素毎に計算するのではなく、必ず行列全体をまとめて計算するようにします。こうすると、Matlabはかなり速いです。(それこそ下手にCやfortranで自分で書くよりずっと速い)
で、今回の場合、非関数版のプログラムのほうでは、おそらくMatlabのJITコンパイラが、ループを行列計算に最適化して実行したのでしょう。
それに対して関数版では、最適化機能が効かずに実際にループとして実行されたのでしょう。
Matlabのループは本当に劇遅なので、VBAより遅いということもありえる話だと思います。
とくに、Matlab でループの中で、行列のサイズを毎回変更するとかすると、信じられないくらいに遅いですよ。
No.3
- 回答日時:
関数を使わないよりは使ったほうが時間が掛かるのは当然ですが、単純に倍率で判断しないほうがいいでしょう。
示された例の場合は、関数が100000×1000回呼び出されたことによる増大ですから、
比率ではなく、差で比較したほうが適切です。
Matlabなら、1分6.8秒
BVAなら、12.41秒
増えたということです。
今回は、kei = i * i * j * j; という単純な計算だから何倍にもなっただけで、
これがもっと時間の掛かる処理、例えば、100000×1000回やって10分掛かるような処理でも、その差は同じですから、
Matlabは、10分と11分6.8秒
BVAなら、10分と10分12.41秒
ということになり、倍率としてはそれほど違いはないでしょう。
1時間掛かるような処理なら、そのくらいの差はほとんど気にならなくなります。
No.2
- 回答日時:
MATLABは使ったことがないですがインタプリタとしては遅いようです。
MATLABを純粋に演算機能だけ比べればVBAよりも速いのも情報通りです。関数呼び出しは、処理後に続きに戻る情報を記録するため基本的に遅いのですが、MATLABは特別遅いのかもしれません。
関数呼び出しを高速に実行するにはコンパイラ系の言語を使ったほうが良いので、FORTANとかであれば問題がほぼありません(若干は速度低下します)。
MATLAB Compilerってもの有る見たいですから使えるのなら使ってみてはどうでしょうか?
http://www.mathworks.co.jp/products/compiler/
No.1
- 回答日時:
一般的に……関数(というかサブルーチン)を使用した場合は、
「サブルーチンから戻る時の戻り先」
「サブルーチン内で使用するローカル変数の領域の確保」
などを記憶して、
「制御をそのサブルーチンの開始位置に飛ばす」
という処理が入ります。
単純なループだけでしたらサブルーチン化した場合に上記のオーバーヘッドが重くなります。
# 言語仕様によるところもあるかと思われますが。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語 3 2022/10/04 15:07
- Excel(エクセル) VBAで組み合わせ算出やCOUNTIFSの処理を高速化したいです。 4 2022/04/07 02:38
- その他(Microsoft Office) Excelで時間計算(負) 8 2023/02/26 05:47
- C言語・C++・C# numpyスライス機能を使った数値計算 2 2023/05/08 16:01
- Visual Basic(VBA) Excel のユーザー定義関数でソルバーが動作しない 1 2022/09/05 19:51
- C言語・C++・C# このプログラミングの問題を教えてほしいです。 キーボードからデータ数nとn個のデータを入力し、平均値 3 2022/12/19 22:51
- Visual Basic(VBA) ファイル全てを .xlsm に変更したところ、プログラムが途中で落ちてしまっています 17 2022/12/07 12:03
- 労働相談 有給休暇使用時の賃金の計算方法について 5 2022/04/04 00:02
- その他(コンピューター・テクノロジー) 50台の織機から回転数を取得・集計しモニターに表示したい 2 2022/11/05 15:48
- その他(ソフトウェア) F-BASICで計算中の実行が中途で勝手に止まり、大変困っています。 2 2023/03/02 16:15
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
入力した数値を倍々するプログラム
-
ループを途中で抜けたいのですが。
-
ループの特定入力終了
-
do-while文が禁止される理由
-
__asm int 3でのブレイクポイン...
-
break文でループを一気に抜ける...
-
C言語、whileループを抜け出す...
-
整定時間
-
Aの値からBの値を除するとは??
-
fgetsなどのときのstdinのバッ...
-
「指定されたキャストは有効で...
-
Enterキーを押されたら次の処理...
-
java初心者です。入力されたの...
-
C言語のステップ数をカウントす...
-
10個出力で改行したいのですが...
-
数字以外が入力されたらエラー...
-
C言語での引数の省略方法
-
2÷3などの余りについて
-
ExcelでPC(パソコン)によって...
-
プログラムでの数字につく”f”の...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
do-while文が禁止される理由
-
入力した数値を倍々するプログラム
-
ループを途中で抜けたいのですが。
-
C言語forループが完結した場合...
-
break文でループを一気に抜ける...
-
C言語、whileループを抜け出す...
-
入力した文字列から母音だけを...
-
プログラムで関数は使わない方...
-
For文の終了値を関数にしても問...
-
Cプログラムが終了しない
-
if文の中にfor文なのか、for文...
-
他言語で言うcontinue文
-
文字列を後ろから1文字ずつ表示...
-
if文を使わずに奇数・偶数を判断
-
整定時間
-
for文while文の無限ループの違...
-
excel VBA if文について
-
n重のfor文にするには?
-
特定の文字列が出てくるまでの...
-
VBScriptでSQLに接続し、CSV出...
おすすめ情報