条件分岐と三項演算子の処理速度。

アバター
うむー
記事: 0
登録日時: 14年前
住所: 茨城県
連絡を取る:

条件分岐と三項演算子の処理速度。

投稿記事 by うむー » 14年前

こんにちは。
Cのモヤモヤの一つで、「1行の条件分岐」をする書き方をちらっと見かけてから、ずーっと分からずにいて、
つい最近「三項演算子」という言葉で知ったのです。
そして書き方をようやく習得して思ったこと。

通常の条件分岐と三項演算子とでは性能差はどのくらい違うのだろう

はい。思ったらやらねばなりません。
というわけで汚ねぃソースですがプログラム書いて確かめてみました!
使ったコンパイラはBorland Cです。

CODE:

#include 
#include 

int main()
{
    int i,j,max;
    clock_t start,end;
	double sa,to1,to2,total;
	to1 = to2 = total = 0.0;
	scanf("%d",&max);
	for(j=0;j<max;j++){
		printf("-------------------------------------------------------------------------------\n");
		printf(" %d 回目のテストです。\n",j+1);
		start = clock();
		i = 100000000;
	    while(i){
			if(i) i -= 1;
			else i -= 0;
	    }
	    end = clock();
	    printf("    条件分岐 : %.5f秒かかりました\n",(double)(end-start)/CLOCKS_PER_SEC);
		to1 += (double)(end-start)/CLOCKS_PER_SEC;
		sa = (double)(end-start)/CLOCKS_PER_SEC;
		i = 100000000;
	    start = clock();
	    while(i){
			i -= (i) ? 1 : 0;
	    }
		end = clock();
		printf("   三項演算子: %.5f秒かかりました\n",(double)(end-start)/CLOCKS_PER_SEC);
		to2 += (double)(end-start)/CLOCKS_PER_SEC;
		sa -= (double)(end-start)/CLOCKS_PER_SEC;
		if(sa < 0.0) printf("      ● %.5f秒 差で 条件分岐 の勝ち~\n",sa*-1.0);
		else printf("      ○ %.5f秒 差で 三項演算子 の勝ち~\n",sa);

	}
	printf("\n\n 平均発表~♪\n");
	to1 /= (double)j;
	to2 /= (double)j;
	total = to1 - to2;
	
	printf("    条件分岐 : %2.5f秒/1億回\n   三項演算子: %2.5f秒/1億回\n\n",to1,to2);
	if(total < 0.0) printf("      ● %.5f秒 差で 条件分岐 の勝ちでした~\n",total*-1.0);
	else printf("      ○ %.5f秒 差で 三項演算子 の勝ちでした~\n",total);
	
	return 0;
}
……結果ですが。

……大して変わらず^^;

コードが悪いのかなあ。それとも内部処理的には全くかわりないのか。
はたまたC#とかになると違ってくるのでしょうかね。

アバター
bitter_fox
記事: 607
登録日時: 14年前

RE: 条件分岐と三項演算子の処理速度。

投稿記事 by bitter_fox » 14年前

CODE:

#include 
#include 

void main()
{
    int i = 1, n = 3;

    if (i < n)
    {
        puts("true");
    }
    else
    {
        puts("false");
    }

    i < n?puts("true"):puts("false");
}
このコードを、アセンブリに出力する(Sをコンパイルオプションに指定すると出力されます)と以下のようになります

CODE:

   ;	
   ;	void main()
   ;	
	push      ebp        ;ebpを使うのでスタック領域に上げる
	mov       ebp,esp ;引数をebpに代入
	push      ebx ;ebxを使うのでスタック領域に上げる
	push      esi ; esiを使うのでスタック領域に上げる
   ;	
   ;	{
   ;		int i = 1, n = 3;
   ;	
@1:
	mov       ebx,1 ; ebxに1を代入(i = 1)
	mov       esi,3 ; esiに3を代入(n = 3)
   ;	
   ;	
   ;		if (i < n)
   ;	
?live1@32: ; EBX = i, ESI = n
	cmp       esi,ebx ; esiとebxを比較したとき
	jle       short @2 ; もし、esiがebx以下だったら @2に飛ぶ
   ;	
   ;		{
   ;			puts("true");
   ;	
	push      offset s@ ; offset s@を第一引数に指定する(offset s@ は "true\0false\0true\0false")
	call      _puts ; putsを呼ぶ
	pop       ecx
   ;	
   ;		}
   ;	
	jmp       short @3 ; @3に飛ぶ
   ;	
   ;		else
   ;		{
   ;			puts("false");
   ;	
@2:
	push      offset s@+5 ; offset s@+5を第一引数として渡す(offset s@+5は"false\0true\0false")
	call      _puts ; putsを呼ぶ
	pop       ecx
   ;	
   ;		}
   ;	
   ;		i<n?puts("true"):puts("false");
   ;	
@3:
	cmp       esi,ebx; esiとebxを比較したとき
	jle       short @4 ; もし、esiがebx以下だったら @2に飛ぶ
	push      offset s@+11 ; offset s@+11を引数に指定する(offset s@+11は"true\0false\0")
	call      _puts ; putsを呼ぶ
	pop       ecx
	jmp       short @5 ; @5に飛ぶ
@4:
	push      offset s@+16 ; offset s@+16を引数に指定する(offset s@+16は"false\0")
	call      _puts ; putsを呼ぶ
	pop       ecx
   ;	
   ;	}
   ;	

@5:
@6:
	pop       esi ; スタック領域に上げていたものを受け取る
	pop       ebx ; 同様
	pop       ebp ; 同様
	ret ; return文

s@	label	byte
	;	s@+0:
	db	"true",0
	;	s@+5:
	db	"false",0
	;	s@+11:
	db	"true",0
	;	s@+16:
	db	"false",0
見た感じ両方とも、比較してesiがebx以下だったら偽の方に飛ばしてそうじゃなかったら真を実行してますね。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前

Re: 条件分岐と三項演算子の処理速度。

投稿記事 by softya(ソフト屋) » 14年前

速度的には、大して変わらないと思いますよ。
一行に書けるのは意味があると思う人もいるだろうし、思わない人もいます。

ちなみに昔はコンパイル速度やらコンパイル時の最適化、実行速度など意味があったのかも知れません。

ISLe
記事: 2650
登録日時: 14年前

Re: 条件分岐と三項演算子の処理速度。

投稿記事 by ISLe » 14年前

三項演算子は式なので↓のように書けます。

CODE:

draw(x, y, bRev ? NORMAL : REVERSE);
if文だと一時変数が必要で命名が面倒なのです。