誰かがこのメソッドを使用して変数をインクリメントするのを見ました:
r = (r + 1) & 0xf;
その方法は、単に使用するよりも優れている/高速ですか:
r++;
なぜ誰かがビットごとに 0xf を使用し、それが複製されるだけなのですか?
誰かがこのメソッドを使用して変数をインクリメントするのを見ました:
r = (r + 1) & 0xf;
その方法は、単に使用するよりも優れている/高速ですか:
r++;
なぜ誰かがビットごとに 0xf を使用し、それが複製されるだけなのですか?
それらは同じではありません。最初のものは r をインクリメントし、それに対してモジュロ演算を実行し、実質的に次と同じことを行います。
r = (r + 1) % 16;
表現:
r = (r + 1) & 0xf;
実際にはこれと同等です (r
が非負であることが保証されていると仮定します):
r = (r + 1) % 16;
このため、上記のいずれのステートメントも と比較することはできませんr++
。そもそも同じことをしているわけではないので、どちらが「速い」か「優れている」かは問題ではありません。
他の人が述べているように、投稿した 2 つのコード スニペットは同等ではありません。その情報に基づいて質問を更新すると、質問は次のようになります。
r = (r + 1) & 0xf;
より良いです か?r = (r + 1) % 16;
前者の表記法の方が適切な状況が考えられるかもしれませんが、一般的には noであり、 ではありません。モジュロ演算子を使用すると、何が起こっているのかがより明確になります。ほとんどのコンパイラがこの最適化を実行すると思います。速度のために可読性を不必要に犠牲にしないでください。(もちろん、考えられる速度の違いを確認したい場合は、両方のスニペットをアセンブラーにコンパイルしてgcc -S
、出力を比較してください。)
編集:以下の nobarの発言は、通常、見た目ほど簡単ではないことを示しています。とは異なり&
、%
は算術演算子であり、いくつかの追加規則にバインドされています (たとえば、負の引数が適切に処理されるようにするため)。上記の 2 つのステートメントは、負でない値または に対してのみ同等ですr
。コンパイラが についてそのような仮定を行うことができるようにするr
には、それを宣言するのが最善unsigned
です。
これらの行は同等ではありません。呼び出し前に r が 15 の場合、最初のものはゼロに戻ります。
r++
右辺値として事前にインクリメントされた値が必要でない限り、インクリメントに使用しないでください。ほとんどのコンパイラは、ポストインクリメント機能が必要ない場合は ++r に最適化しますが、それに依存しないことをお勧めします。しかし、あなたはおそらく と の比較を求めるつもりだったので、コードの理解と維持がより困難であることに比べれば、後者が特定のコンパイラまたはハードウェアを持っている可能性があるというわずかな改善は重要ではないと私は提出します++r
。(r + 1) & 0xf;
一般に、他のアーキテクチャーには当てはまらない可能性のある最適化を過度に巧妙にしようとすることは避けてください。
あなたが与える2つのコード例には同等のものはありません。
1) 値を 0 から 15 に制限し、値が 15 を超えるとゼロにラップアラウンドする高速な方法です。
2) 上限なしで値をインクリメントするだけです ( r が宣言されている型、つまり、r が unsigned char などとして宣言されている場合は > 255 でラップされます)
1)これを行うことと同等です
if (r + 1 > 15 )
{
r = 0;
}
したがって、ブランチなどの必要性がなくなるため、特定の種類のハードウェアではより最適な場合があります。
r が整数の場合、 と を任意の種類のコンパイラ最適化と比較する
r=(r+1) & 0xf;
と、それらは同じになるはずです。
++r;
r %= 0x10;
おそらく、コードを保守するプログラマーにとってどの方法が明確で理解しやすいかを自問する必要があります... C と C++ は同じことを言うために多くの構文を提供し、コンパイラーはほとんどの状況でプログラマーよりも賢いので、責任はコードを理解しやすくします。