- ベストアンサー
関数を使わない方がプログラムは速くなる?
- 大きなプログラムを書く際、関数を多用することでプログラムの見通しが良くなり、後から修正しやすくなる。
- しかし、関数を使用すると計算速度が低下する可能性がある。
- 関数を使用しない場合には、Matlabが最速で、関数を使用する場合にはVBAが最速になることが分かっている。
- みんなの回答 (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の最適化機能はあまり頭が良くないので、かなり単純な構造じゃないと、ループを行列演算に自動変換してくれません。 なんで、基本的には、ユーザーが上記のように、明示的にきちんとループではなくて行列演算の形で記述する必要があります。
その他の回答 (7)
- rabbit_cat
- ベストアンサー率40% (829/2062)
#4です。 ちょっと、きちんと言いたいことの本質が伝わらないかもと思ったので補足。 matlabに関して言えば、100倍遅くなった原因は、 ・関数呼び出しにしたから ではなくて、 ・ループ(for文)を使ったから です。 一見、両方とも、ループが存在しているように見えますが、関数版でないほうは、matlabが内部でプログラムを自動的に解析して、内部で、ループではなくて行列計算になるように変更して実行されたため速いのです。 関数版のほうは、最適化が利かなくなってしまったため、実際にループとして実行されたので、劇遅になってしまったわけです。 >2倍程度なら許容範囲ですが、100倍以上も遅くなるのであれば、 >関数は全く使うべきではない、ということになりますが、なぜこれほどまでに時間がかかるのでしょうか? matlabに関して言えば、関数呼び出し自体は当然使用してもよいですが、大規模なループ(for文)は使用すべきではありません。(それこそ100倍遅くなります)
> 2倍程度なら許容範囲ですが、100倍以上も遅くなるのであれば、 > 関数は全く使うべきではない、ということになりますが、... それは極論ですね。速度のボトルネックの多くはプログラムのごく一部です。速度のチューニングは後回しにして、関数を多用する質問者さんの従来のスタイルが正しいと思います。 逆に関数を使わないと、アルゴリズムのボトルネックを探すことが難しくなるでしょう。プロファイラ等で時間計測することが難しくなってしまうので。 しかし最適化すべき部分と期限が決まったなら、どんな手段もためらうべきではないとは思います。
- kinta03
- ベストアンサー率41% (7/17)
お疲れ様です。 抽象的な説明ですが参考に為れば幸いです。 例えば次のような関数が有ったとします。 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は関数を使わなければそのまま行っている事ですよね。 簡単な演算なのでオーバーヘッドが物凄く多く感じますが 処理内容によっては無視できる範囲になります。 今回のように呼び出し回数が多い場合にはオーバーヘッドばかり増えますよね。 そこのところを考えて判断してください。
- rabbit_cat
- ベストアンサー率40% (829/2062)
どう書くのが速いか、言語と、コンパイラやインタプリタの最適化機能によるので一般論では言えません。 通常は、まったく同じ内容を関数化すれば、最適化が効き難くなる分だけ遅くなることが多いとは思いますが、場合によっては、関数化することで、コンパイラの中での最適化用で考えないと行けないスコープが狭まることで、逆に最適化が効きやすくなって高速化する場合もあります。 その上で、Matlabに限定した話ですが。 まず、Matlabでは、基本的に、for文などのループは劇遅なので使ってはいけません。 ループで行列の要素毎に計算するのではなく、必ず行列全体をまとめて計算するようにします。こうすると、Matlabはかなり速いです。(それこそ下手にCやfortranで自分で書くよりずっと速い) で、今回の場合、非関数版のプログラムのほうでは、おそらくMatlabのJITコンパイラが、ループを行列計算に最適化して実行したのでしょう。 それに対して関数版では、最適化機能が効かずに実際にループとして実行されたのでしょう。 Matlabのループは本当に劇遅なので、VBAより遅いということもありえる話だと思います。 とくに、Matlab でループの中で、行列のサイズを毎回変更するとかすると、信じられないくらいに遅いですよ。
- nag0720
- ベストアンサー率58% (1093/1860)
関数を使わないよりは使ったほうが時間が掛かるのは当然ですが、単純に倍率で判断しないほうがいいでしょう。 示された例の場合は、関数が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時間掛かるような処理なら、そのくらいの差はほとんど気にならなくなります。
- zwi
- ベストアンサー率56% (730/1282)
MATLABは使ったことがないですがインタプリタとしては遅いようです。MATLABを純粋に演算機能だけ比べればVBAよりも速いのも情報通りです。 関数呼び出しは、処理後に続きに戻る情報を記録するため基本的に遅いのですが、MATLABは特別遅いのかもしれません。 関数呼び出しを高速に実行するにはコンパイラ系の言語を使ったほうが良いので、FORTANとかであれば問題がほぼありません(若干は速度低下します)。 MATLAB Compilerってもの有る見たいですから使えるのなら使ってみてはどうでしょうか? http://www.mathworks.co.jp/products/compiler/
- Wr5
- ベストアンサー率53% (2173/4061)
一般的に……関数(というかサブルーチン)を使用した場合は、 「サブルーチンから戻る時の戻り先」 「サブルーチン内で使用するローカル変数の領域の確保」 などを記憶して、 「制御をそのサブルーチンの開始位置に飛ばす」 という処理が入ります。 単純なループだけでしたらサブルーチン化した場合に上記のオーバーヘッドが重くなります。 # 言語仕様によるところもあるかと思われますが。
お礼
皆さんご回答ありがとうございます。 遅くなる原因は理解することができました。 もう一つ関連した質問をお聞きしたいのですが、 関数に変数のやり取りをしているために遅くなる、というのであれば、 グローバル変数を使ってやれば、引数のやり取りだけはなくなり、その分速くなるのではないかと思い 試してみました。 計算回数を一桁下げて 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倍も計算速度が遅くなるのでしょうか?