私が得た答えに基づいて、この問題は無意味だと思います。親切な返信ありがとうございます。
右端のjビットが1、その他が0の2進数を取得したいのですが、基本的には2つの方法があります。どちらがより効率的か知りたいですか、またはこれら2つよりも効率的な方法はありますか?
1. ~(~0 << j)
2. (1 << j) - 1
私が得た答えに基づいて、この問題は無意味だと思います。親切な返信ありがとうございます。
右端のjビットが1、その他が0の2進数を取得したいのですが、基本的には2つの方法があります。どちらがより効率的か知りたいですか、またはこれら2つよりも効率的な方法はありますか?
1. ~(~0 << j)
2. (1 << j) - 1
それがあなたが探している答えであるかどうかはわかりませんが、ナノ秒以上の違いはないと思います。:)
または、別の言い方をすれば、そのワンライナーがコードのボトルネックでない限り、マイクロ最適化しないでください。
実際には遅くなる可能性のある他の形式の高速ビット操作が必要な場合は、などのコンパイラ組み込み関数を調べてみてください_BitScanForward
。これらを正しく使用すると、実際にビット演算が高速になる可能性があります(ただし、このような状況ではそうではありません)。
あなたはマイクロ最適化しています。コンパイラは、これらの操作に最適な翻訳を知っています。人間の目に最もきれいに見えるものを書いて、次に進んでください。
すでに投稿されたコメントに加えて:
ベンチマークに加えて、放出されたアセンブラーを調べます。オプティマイザーは、それぞれに対して同じコードを生成した可能性があります。
本当に最速の が必要な場合は、ルックアップ テーブルを使用します。
const unsigned numbers[] = {
0x00000000,
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
unsigned h(unsigned j) {
return numbers[j];
}
これを 64 ビットに拡張することは、読者の課題として残されています。そして、他の人が言ったように、これは問題ではありません。
これは一種の怠惰な答えですが、次のような簡単なプログラムを書いてみましたか? 確かにマイクロ最適化ですが、違いがあるかどうかを確認するのは楽しく興味深いかもしれません。
#include <ctime>
main()
{
int i;
time_t start = time();
for (i = 0; i < 1000000; i++)
{
// your operation here
}
time_t stop = time();
double elapsed = difftime(stop, start);
}
0
に変更しない限り0U
、式~(~0 << j)
にはビット パターンに基づく実装固有の動作があります。一方、式(1 << j) - 1
は純粋に算術演算であり、ビット演算を含まないため、その値はすべての実装で明確に定義されています。したがって、私は常に後者を使用します。
本当の答えは、おそらくプロセッサアーキテクチャに依存しています。しかし、すべての意図と目的のために、それはほぼ確実に無関係です。また、コンパイラがどちらの方法でも同じアセンブリを出力する可能性があることを考慮してください。本当に知る必要がある場合は、ベンチマークを行ってください。ただし、違いはほぼ確実に小さすぎて測定できません(これがあなたの答えですが、問題ではありません)。
タイミング実験は必要ありません。生成されたマシン コードをチェックするだけです。gcc が両方を同一の機械語命令にコンパイルすることがわかります。