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

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

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

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

7回答

29417閲覧

if文の書き方で速度の違いは生じますか?

bouyomisan

総合スコア87

C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

3クリップ

投稿2017/07/25 08:20

初歩的な質問ですみません。or 条件で処理をする時複数の書き方が3パターン存在すると思いますが、どのような書き方が早い処理をできるのでしょうか?

2番目と3番目は結構無理やりですが、単純にこういう書き方をした時の速度の違いが知りたいので書きました

if(joken1 || joken2 ||joken3){ //処理1 }

if(jogen1){ //処理1 }else if(jogen2){ //処理1 }else if(joken3){ //処理1 }

if(joken1){ //処理1 } if(joken2){ //処理1 } if(joken3){ //処理1 }
LouiS0616👍を押しています

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

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

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

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

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

guest

回答7

0

処理速度の前に、これらの3つですが、処理として意味合いが異なってきます。

c++

1if (joken1 || joken12 || joken3) { 2 //ここの処理はjoken1,joken2,joken3の少なくとも1つがtrueなら処理される 3} 4 5if (joken1) { 6 //joken1がtrueの時処理される 7} else if (joken2) { 8 //joken1がfalseでjoken2がtrueの時に処理される 9} else if (joken3) { 10 //joken1とjoken2がfalseでjoken3がtrueの時に処理される 11} 12 13if (joken1) { 14 //joken1がtrueの時処理される 15} 16if (joken2) { 17 //joken1と関係なくjoken2がtrueの時処理される 18} 19if (joken3) { 20 //joken1,joken2と関係なくjoken3がtrueの時処理される 21} 22

となりますので、

  • 処理がどういうものか?
  • その条件は何なのか?
  • 各条件に依存関係はあるのか?

など考慮した上でどういうロジックにするのかを考える必要があります。

つまり、もし、「処理1」全て同じなら、1番目と2番めは「処理1」は1回しか処理されないが、3番めはjoken1,2,3が全てtrueの場合3回「処理1」を実行してしまうということです。(処理速度よりロジックを考えるべき)

質問の処理速度について一応答えておくと、joken1,joken2,joken3が全てtrueの場合、3番めの処理は「処理」が3回実行されることになるので一番時間がかかることになるでしょう。

2番めは、joken1,joken2,joken3の状態によって変わります。joken1がtrueならそのチェックだけで処理が実行されますが、joken1,joken2がfalseならjoken3のチェックまで行われるのでその分時間は掛かります。(と言っても一瞬ですけどね)

1番めは、joken1,joken2,joken3の状態によって処理速度は「たぶん」変わりません。(「たぶん」というのは、コンパイラーが吐き出すコードに依存します。条件の評価が仮に先頭からとして全て||で繋いでいるので1つでもtrueがあったら処理を実行するようなコードを吐き出すコンパイラなら、joken1,2,3の状態に依存することになります。)

ただ、joken1,joken2,joken3がboolなどの変数なら、条件のチェックは一瞬で終わるので、「処理」の内容に速度は依存することになるでしょうね。(この処理を数万回繰り返すのなら別ですが)

投稿2017/07/25 08:53

PineMatsu

総合スコア3579

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

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

nobuzoh

2017/08/01 00:56

余談ですが、 2、3は人間の目にも処理順は明らかですが、 1の「たぶん」について、 きっと平均的に速くなるようにはしてるんでしょうが、 実際の所ってどうなのか気になりました。 コンパイラや言語毎に試した人っていないかなー。
PineMatsu

2017/08/01 07:55

コンパイラの最適化技術は目をみはるものがあるので、殆ど変わらないように思います。何100万回か実行してようやく差が出るくらいでしょうかね?
guest

0

回答としては Chironian さんに一票ですが、コンパイラの最適化の話があるので、少し実験してみました。1番目と2番目の比較について、

C

1#include <stdio.h> 2extern int i; 3extern init(int); 4extern process1(); 5 6 7void test1() { 8 if (i < 3 || i ==5 || i == 7) { 9 process1(); 10 } 11} 12 13void test2() { 14 if (i < 3) { 15 process1(); 16 } else if (i == 5) { 17 process1(); 18 } else if (i == 7) { 19 process1(); 20 } 21} 22 23int main(){ 24 init(3); 25 test2(); 26 test1(); 27} 28

これを cc -c a.c -O2 でコンパイルしてディスアセンブルすると、

asm

10000000000000000 <test1>: 2 0: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 6 <test1+0x6> 3 6: 89 c2 mov %eax,%edx 4 8: 83 e2 fd and $0xfffffffd,%edx 5 b: 83 fa 05 cmp $0x5,%edx 6 e: 74 10 je 20 <test1+0x20> 7 10: 83 f8 02 cmp $0x2,%eax 8 13: 7e 0b jle 20 <test1+0x20> 9 15: f3 c3 repz retq 10 17: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 11 1e: 00 00 12 20: 31 c0 xor %eax,%eax 13 22: e9 00 00 00 00 jmpq 27 <test1+0x27> 14 27: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 15 2e: 00 00 16 170000000000000030 <test2>: 18 30: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 36 <test2+0x6> 19 36: 83 f8 02 cmp $0x2,%eax 20 39: 7e 0d jle 48 <test2+0x18> 21 3b: 83 e0 fd and $0xfffffffd,%eax 22 3e: 83 f8 05 cmp $0x5,%eax 23 41: 74 05 je 48 <test2+0x18> 24 43: f3 c3 repz retq 25 45: 0f 1f 00 nopl (%rax) 26 48: 31 c0 xor %eax,%eax 27 4a: e9 00 00 00 00 jmpq 4f <test2+0x1f> 28

ほぼ、同じコードが出ていることがわかります。 catsforepaw さんのおっしゃるとおり、大胆に改変されていますが、この程度の単純な条件式であれば、2番めのパターンでも1番目と同様に最適化してしまいますね。test2() で process1() の呼び出しは3個書いても1個しかでてませんし、比較条件の順番が入れ替わってますが、やってる内容はほぼ同じです。

しかし、 == 7 を比較するのに2ビット目をマスクして == 5 の比較を共用するとは・・・

私の結論としては、2番めでも速度的には1番目と変わりませんが、保守性の問題で1番目で書くべきだと思います。

テスト環境は Centos 7 x86_64 で、コンパイラのバージョンは
cc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11)
です。

投稿2017/08/01 02:57

mit0223

総合スコア3401

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

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

0

ほかの方もおっしゃっているとおり、1番目と2番目は同じ結果になりますが、3番目は明らかに無駄な処理が発生する(場合によっては処理結果が異なる)ので比較対象からは外すべきでしょう。

ということで、1と2に絞って速度に違いがあるかどうかですが、結論から言うと違いが出る可能性があるということになります。さらに言えば、1番目の方が速くなる可能性が高いです。

その理由はコンパイラーの最適化です。最適化においては、関連する処理(特に計算処理)が近い場所にあると最適化が効きやすいという性質があるためです。

1番目のコードはjoken1~3が一続きの式になっていて、最終的に処理1にたどり着きます。一方、2番目の方は、joken1~3が異なるif文に分かれていて、さらに、処理1も同様に分かれています。処理内容にもよりますが、1番目の方が最適化が効きやすいのは一目瞭然です。

今時のコンパイラーはとても賢いので、最適化を有効にすると計算式を「解析」して結果を損なわない範囲で「(大胆に)改変」します。

例えば、

if(x == 1 || x == 2 || x == 3) { 処理 }

このようなコードは最適化によって

// ※擬似コード if((unsigned)x - 1 <= 2) { 処理 }

のように「改変」されたりします。

投稿2017/07/25 12:10

catsforepaw

総合スコア5938

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

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

0

こんにちは。

1番目の記述は、事実上2番目と同じです。 || で繋いだ場合、左側の式がtrueになると右側の式は評価されません。短絡評価と呼ばれてます。

ただし、2番目は「処理1」を3回書きます。「処理1」を修正したい時、同じ修正を3回行う必要があります。無駄に修正漏れのリスクがあるメンテナンス性の悪いコードです。

3番目は他の処理と内容が異なりますので、比較するべきではありません。
条件により「処理1」を最大3回実行します。それが必要であるにも関わらず1番目や2番目のように記述するとバグとなります。

投稿2017/07/25 09:04

Chironian

総合スコア23272

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

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

0

題意とは外れますが、ちょっと別の角度から・・・
一般的に同格率で起こる条件というのは稀です。従って、1や2の場合は一番発生しやすい条件を先頭に持ってくるようにします。(判定回数が減るため)処理速度が上がります。・・・今のCPUじゃほとんど効き目が無いかもですが・・・プログラマにしかできない最適化ですd^^;

投稿2017/08/06 12:24

cateye

総合スコア6851

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

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

0

1と2は差はないはずです。
3は明らかに遅くなりますし、jokenが排他でないなら複数回処理されるので、明らかにNGでしょう。

if文の評価の仕方について、私も気にしたことがありますが、
意識するレベルで処理速度に差異はでないと思います。

人が読みやすいことを気にしたほうがよいです。

※2のような書き方をしてあったら、実装ミスをうたがう人が多いと思います

投稿2017/07/25 08:48

momon-ga

総合スコア4820

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

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

0

処理速度云々の前に
2番目のコード

if(jogen1){ //処理1 }else if(jogen2){ //処理1 }else if(joken3){ //処理1 }

3箇所に全く同じ処理「処理1」を記述するのはどうかと思うけど・・・
普通に考えると、上記のようなコーディングをされると、それぞれ別の処理「処理1」「処理2」「処理3」が記述されるはずだけど、ぱっと見同じっぽい。バグっぽいな・・・。
と感じてしまうと思う。

因みに、3番目のコードは

if(joken1){ //処理1 return; } if(joken2){ //処理1 return; } if(joken3){ //処理1 return; }

とすれば、2番目と一緒かと。

いずれにせよ、「普通」ではないと思う。

投稿2017/08/11 13:07

o8q

総合スコア18

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問