ページ 1 / 1
3項演算
Posted: 2019年3月01日(金) 21:40
by h1j1k1
コード:
max = max < fixstat[i] ? fixstat[i] : max;
min = min > fixstat[i] ? fixstat[i] : min;
コード:
if(max < fixstat[i]) max = fixstat[i];
if(min > fixstat[i]) min = fixstat[i];
3項演算子の是非についてはいろいろありますが、はたしてどっちがいいのでしょうか?
やりたいことは
fixstat
が過去最大(max)より大きかったらmaxに代入
fixstatが過去最少(min)より小さかったらminに代入
どれでもないならスルー
Re: 3項演算
Posted: 2019年3月02日(土) 02:58
by box
結果さえ正しければ、どっちでもいいです。
Re: 3項演算
Posted: 2019年3月02日(土) 15:51
by reika
これはあくまでも個人的意見なのですが、if文と三項演算子はそもそも何者なのかを考えると、使い分けのヒントになると思います。
if文というのは「制御文」で、「条件に応じて処理を分岐させる」のが役割です。
よって次のようなコードが書けます。
コード:
if(hoge){
func1();
}else{
func2();
}
これは「hogeが真なら関数func1を実行し、偽ならfunc2を実行する」というコードですね。
さてそれに対し三項演算子ですが、これは「演算子」です。「演算子」というのは「いくつかの値を受け取り、それに応じた値を返す」ものです。例えば加算演算子"+"は、数を二つ受け取り、その和を返します。別の例として関係演算子"=="は両辺の値が等しいならtrueを、等しくないならfalseを返します。
三項演算子も同じです。三項演算子の場合三つの値を受け取り、それに応じて値を返します。
コード:
a?b:c // aが真ならbを、偽ならcを返す
よって、結局のところ「条件によって全く違う処理をさせる」ことが目的ならif文で分岐させ、「条件によって違う値を返させる」ことが目的なら三項演算子を使うのがスマートではないかと思います。なので私の意見としては、今回のケースではif文より三項演算子を使うのが適切ではないかと思います。
また、h1j1k1様が提示された最大値や最小値を求めるようなケースであればこんな書き方もいいのではないかと思います(私はいつもこうしています)。
コード:
// szはfixstatの要素数
// 最大値を入れる変数の名前はmaximumとする(max関数と紛らわしいため)
for(int i=0;i<sz;++i){
maximum=max(maximum,fixstat[i]);
}
お疲れさまでした。
Re: 3項演算
Posted: 2019年3月03日(日) 13:17
by あたっしゅ
min, max であれば、
https://ja.cppreference.com/w/cpp/algorithm/max
std::max - cppreference.com(ja)
https://www.gesource.jp/weblog/?p=7660
Visual Studio で std::min()/std::max() がエラーになるときの回避策 - 山本隆の開発日誌(ja)
std::min と std::max を使うべき。
Re: 3項演算
Posted: 2019年3月03日(日) 17:34
by みけCAT
Compiler Explorerで試したところ、
if文を用いても三項演算子を用いてもcmovg命令を用いた全く同じコードに最適化される例を確認できました。
► スポイラーを表示
コンパイルしたコード
コード:
int smallest(int* arr, int size) {
int ans = arr[0];
for (int i = 1; i < size; i++) {
if (ans > arr[i]) ans = arr[i];
}
return ans;
}
int smallest2(int* arr, int size) {
int ans = arr[0];
for (int i = 1; i < size; i++) {
ans = ans > arr[i] ? arr[i] : ans;
}
return ans;
}
コンパイラ:x86-64 gcc 8.2 、-O2オプション使用)
コンパイル結果
コード:
smallest:
mov eax, DWORD PTR [rdi]
cmp esi, 1
jle .L1
lea ecx, [rsi-2]
lea rdx, [rdi+4]
lea rsi, [rdi+8+rcx*4]
.L3:
mov ecx, DWORD PTR [rdx]
cmp eax, ecx
cmovg eax, ecx
add rdx, 4
cmp rdx, rsi
jne .L3
.L1:
ret
smallest2:
mov eax, DWORD PTR [rdi]
cmp esi, 1
jle .L6
lea ecx, [rsi-2]
lea rdx, [rdi+4]
lea rsi, [rdi+8+rcx*4]
.L8:
mov ecx, DWORD PTR [rdx]
cmp eax, ecx
cmovg eax, ecx
add rdx, 4
cmp rdx, rsi
jne .L8
.L6:
ret
あまり賢くない特定のコンパイラを使わなければならない上にパフォーマンスが非常に重要である、
「間違った」方を使うとテストで不正解にされたり怒られたりする、
などの特別な事情が無いのであれば、好きな方を使えばいいでしょう。
Re: 3項演算
Posted: 2019年3月03日(日) 17:44
by みけCAT
コードゴルフをする場合は、三項演算子の方が1バイト短くできて良さそうです。
コード:
m=m>f[i]?f[i]:m;
if(m>f[i])m=f[i];
// おまけ
m>f[i]?m=f[i]:1;
m>f[i]&&(m=f[i]);
m+=(f[i]-m)*(m>f[i]);