ここにいくつかの過度に複雑な答えがあります。デブリンテクニックは、入力がすでに2の累乗である場合にのみ使用する必要があります。それ以外の場合は、より良い方法があります。入力が2のべき乗の場合、Debruinは、_BitScanReverse
私がテストしたどのプロセッサよりも、絶対的に高速であり、さらに高速です。ただし、一般的なケースでは_BitScanReverse
(またはコンパイラでコンパイラ組み込み関数が呼び出された場合)、最も高速です(ただし、特定のCPUではマイクロコード化できます)。
組み込み関数がオプションではない場合、一般的な入力を処理するための最適なソフトウェアソリューションを以下に示します。
u8 inline log2 (u32 val) {
u8 k = 0;
if (val > 0x0000FFFFu) { val >>= 16; k = 16; }
if (val > 0x000000FFu) { val >>= 8; k |= 8; }
if (val > 0x0000000Fu) { val >>= 4; k |= 4; }
if (val > 0x00000003u) { val >>= 2; k |= 2; }
k |= (val & 2) >> 1;
return k;
}
このバージョンは、他のほとんどの回答とは異なり、最後にDebruinルックアップを必要としないことに注意してください。所定の位置を計算します。
ただし、テーブルを何度も呼び出すと、キャッシュミスのリスクがテーブルの高速化によって損なわれる可能性があります。
u8 kTableLog2[256] = {
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
};
u8 log2_table(u32 val) {
u8 k = 0;
if (val > 0x0000FFFFuL) { val >>= 16; k = 16; }
if (val > 0x000000FFuL) { val >>= 8; k |= 8; }
k |= kTableLog2[val]; // precompute the Log2 of the low byte
return k;
}
これにより、ここに示したソフトウェアの回答の中で最高のスループットが得られますが、たまにしか呼び出さない場合は、最初のスニペットのようなテーブルフリーソリューションをお勧めします。