質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

5回答

10257閲覧

変数を使った場合と使わない場合の速度の違い

otftrough

総合スコア476

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

12グッド

1クリップ

投稿2016/02/01 11:01

ひとつの値を何度も使う場合は、変数を使ったほうが速く軽くなるのでしょうか?
例えば、

java

1 //if(searchTagName("audio", str)); 2 3 private boolean searchTagName(String name,String str){ 4 5 return str.substring( 6 str.indexOf("<"), 7 str.substring(str.indexOf("<")).indexOf(" ") + str.indexOf("<") 8 ).equals("<" + name); 9 }

と書く場合と、

java

1 //if(searchTagName("audio", str)); 2 3 private boolean searchTagName(String name,String str){ 4 5 int index = str.indexOf("<") 6 return str.substring( 7 index, 8 str.substring(index).indexOf(" ") + index 9 ).equals("<" + name); 10 }

と書く場合では違いますか?

ryunix, hsk, lv_sane, mukaiyuan, syuvarie, arly_times, MIURA_Yasuyuki, afroscript, k_fujimoto, kozuchi, 他2名👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

書いているうちに解決済みになってしまったようですが、上と下では明らかに違いますね。上のコードではstr.indexOf("<")が3回実行されるのに対して、下のコードでは1回なので、下の方が速いと言えます。
同じ計算(処理)はあらかじめ行って変数に入れておき、それを使い回すことで処理回数を減らすというのはパフォーマンスアップの定石です。

実はコンパイラもそれなりに賢くて、「最適化オプション」を付けてコンパイルすると、ループ処理において

C

1for(int i = 0; i < 100; i++) 2{ 3 x[i] += a + b; 4} 5```というコードを、内部的に 6```C 7int tmp = a + b; 8for(int i = 0; i < 100; i++) 9{ 10 x[i] += tmp; 11} 12```このように処理します。ループに入る前にあらかじめ計算してそれを使い回すことでパフォーマンスをアップしようということです。 13ただし、過信は禁物なので、やはり自分でプログラムを見直して、何度も同じ処理を繰り返していないか、まとめて1回で済ませられないか、ということを意識することが重要です。

投稿2016/02/01 12:12

編集2016/02/01 12:32
catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otftrough

2016/02/03 13:45

そうですね、見直せばその分見やすいプログラム文にできますし、自分で改良できる場所を見つけたらしといて損はないかなって感じですね。
guest

0

厳密には、言語とコンパイラおよびコンパイラオプションによりますが、呼び出す関数(メソッド)が高コストの場合は一般的に速くなります。

質問にあるコードですとstr.indexOf("<")がとても重い処理であれば、速度は大きく異なります。なぜなら、上のコードは3回呼び出されるのに対し、下のコードは1回しか呼び出されないからです。最適化がなければコードの通りに呼び出されますので、回数が多くなる方が不利になります。とくに最適化ができないスクリプト言語ではこの速度の違いが顕著に表れるます。

場合によっては、最適化によって呼び出しが一回で済むようにコンパイラが書き換えてくれるときがあります。ただし、それは、対象が参照透過である時のみです。なぜなら、もし関数が、その評価により何かの値が変わる(副作用)、または、呼び出し毎に結果が変わる、といった場合(つまり、参照透過ではない場合)、呼び出し回数によって動作が変わる可能性があるからです。逆に、そのような副作用や別の値になる可能性が無い場合は、わざわざ律儀に何回も呼び出さず、1回目の結果を再利用する形で最適化してくれます。

Haskellで例を示します。(ソースコード名はtest.hsとしています)

Haskell

1import Debug.Trace 2plpl a b = trace "call..." $ a + b 3main = print $ (plpl 3 5) + (plpl 3 5)

plpl関数はただの足し算ですが、デバッグ用のtrace関数により、呼び出したときは"call..."というメッセージを出すようにしています。これによってplpl関数が何回呼び出されたかが判断できます。実際にrunhaskell(Haskellのインタプリンタ)で実行すると下記のようになります。

$ runhaskell test.hs call... call... 16

plplmain内で2回書いているので、コードの通り2回呼び出されました。では、今度はちゃんとコンパイルします。(-Oは最適化オプションです)

$ ghc -O test.hs [1 of 1] Compiling Main ( test.hs, test.o ) Linking test ... $ ./test call... 16

plplは参照透過であり※、その引数も同じ3と5ですので、コンパイラは2回呼び出す必要は無いと判断し、1回の呼び出しだけで動作するようにしてくれました。そのため、plpl関数は1回しか呼び出されません。
※ デバッグ用のtraceによる副作用は無かった物として扱われます。

なお、ほとんどの言語では、定数を除き、変数や関数が参照透過であることをコンパイラが判断することが難しいことがあります。そのため、上のような最適化はHaskellのような純粋関数型言語以外では過度の期待はできないでしょう。


補足
catsforepawさんの回答の例で言うと、C言語の+演算子が参照透過であることをC言語のコンパイラが知っていますので、aとbが変わらない(その範囲内でaとbが参照透過である)ことをコンパイラが判断できれば、最適化してくれます。ですが、C++のオーバーロードされた+演算子や他の一般的な関数では、インライン展開が出来るなどの条件が揃わないとその判断が困難ですので、やはり過信は禁物です。

投稿2016/02/01 12:24

編集2016/02/02 10:03
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

catsforepaw

2016/02/02 03:25

> C++だと+演算子はオーバーロードによりどうなるかわかりませんし、他の一般的な関数ではその判断はほぼ不可能ですので、 インライン展開可能なケースではそれなりに賢く処理できていますね。試しに適当にクラスを作って演算子のオーバーロードやメソッド呼び出しを含む処理をループでさせてみましたが、ちゃんとループ前に計算して結果を使い回すコードが出力されていました。 おそらくインライン展開後のコードを最適化していると思われます。
raccy

2016/02/02 10:14

> catsforepawさん インライン展開という手がありましたね。文言、修正してみました。中身がコンパイラから見えない外部関数であっても、純粋関数であることを指定することで最適化してくれる機能があればいいのですが… と調べたら、GCCではpureなるものがありました。 https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html さらにD言語だと言語仕様としてpure関数があるようです。 http://www.kmonos.net/alang/d/function.html D言語恐るべし…
guest

0

最近のコンパイラの最適化技術はStripeさんも書かれているようにかなり賢いらしいので、実行する際の呼び出し回数が両手で数える程度であればほとんど差はないと思います。ただ、これがループ内などで連続して何千回、何万回と呼び出される可能性があるなら、都度実行速度を計測して最速となる記述を調べる意味はあると思います。

とはいえ、コーディングのスタイルとして、理屈上早くなるであろう書き方や不具合の入り込みにくい書き方を追求するのは正しい姿勢だと思います。

今回の件では、私は後者の書き方の方がデバッグしやすく、なおかつ理屈の上では速度的にも無駄が少なくなる記述だと思います(実際には上記のとおり、数千~のオーダーで連続して実験する必要がありますが……)。

投稿2016/02/01 12:12

KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

話がそれるようなことですが、Java、C#については実行時最適化が行われるため、よほどのことがない限り速度を気にしてコードを書く必要はないです。経験上、メモリの使用によるパフォーマンス低下の方が多いので変数のライフサイクルに気をつけてください。

投稿2016/02/09 13:51

zoppa_software

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otftrough

2016/02/09 18:38

プログラムの無駄より、メモリ(変数)のムダを省いたほうがいいのですね。
guest

0

コンパイルした結果、変数が無くなったり、暗黙的な変数が作られたりすることがあります。
変数の有無で実行速度を制御する事は出来ません。

投稿2016/02/01 11:05

Stripe

総合スコア2183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otftrough

2016/02/01 12:01

ありがとうございます
chooser

2016/02/09 05:16

間違っている記述だと思います
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問