ループなしでC ++のintからN個の最も重要な非ゼロビットを抽出する
-
16-12-2019 - |
質問
C ++の整数からN個の重要なビットを抽出し、それらのNビットを整数に変換したい。
例えば
ですint a=1200;
// its binary representation within 32 bit word-size is
// 00000000000000000000010010110000
.
今、その表現から4桁の4桁を抽出したい、1111
00000000000000000000010010110000
^^^^
.
を再び整数に変換します(10進数= 9の1001)。
ループなしの単純なC ++関数でどのようなものでも可能ですか?
解決
一部のプロセッサには、整数の先頭のバイナリゼロをカウントする命令があり、コンパイラによってはその命令を使用できるようにInstrincesicsがあります。たとえば、GCCを使用して:
uint32_t significant_bits(uint32_t value, unsigned bits) {
unsigned leading_zeros = __builtin_clz(value);
unsigned highest_bit = 32 - leading_zeros;
unsigned lowest_bit = highest_bit - bits;
return value >> lowest_bit;
}
.
簡単にするために、要求されたビット数が利用可能であることを確認しました。Microsoftのコンパイラの場合、組み込み関数は__lzcnt
と呼ばれます。
コンパイラがその組み込み内のものを提供していない場合、プロセッサに適した命令がない場合は、ゼロをすばやくカウントする1つの方法がバイナリ検索である:
unsigned leading_zeros(int32_t value) {
unsigned count = 0;
if ((value & 0xffff0000u) == 0) {
count += 16;
value <<= 16;
}
if ((value & 0xff000000u) == 0) {
count += 8;
value <<= 8;
}
if ((value & 0xf0000000u) == 0) {
count += 4;
value <<= 4;
}
if ((value & 0xc0000000u) == 0) {
count += 2;
value <<= 2;
}
if ((value & 0x80000000u) == 0) {
count += 1;
}
return count;
}
. 他のヒント
それは速くはありませんが、(int)(log(x)/log(2) + .5) + 1
はあなたに最も重要なゼロ以外のビットの位置を伝えます。アルゴリズムを仕上げするのはかなり簡単です。
これはうまくいっているようです(uint32を使ってC#で行われてから、Bjarneへの謝罪するように移植されます):
unsigned int input = 1200;
unsigned int most_significant_bits_to_get = 4;
// shift + or the msb over all the lower bits
unsigned int m1 = input | input >> 8 | input >> 16 | input >> 24;
unsigned int m2 = m1 | m1 >> 2 | m1 >> 4 | m1 >> 6;
unsigned int m3 = m2 | m2 >> 1;
unsigned int nbitsmask = m3 ^ m3 >> most_significant_bits_to_get;
unsigned int v = nbitsmask;
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -((int)v);
if (v>0) c--;
if ((v & 0x0000FFFF) >0) c -= 16;
if ((v & 0x00FF00FF) >0) c -= 8;
if ((v & 0x0F0F0F0F) >0 ) c -= 4;
if ((v & 0x33333333) >0) c -= 2;
if ((v & 0x55555555) >0) c -= 1;
unsigned int result = (input & nbitsmask) >> c;
.
私はあなたが整数数学のみを使用していることを意味していると仮定しました。
私は@ Olicharlesworthのリンクからいくつかのコードを使用しました、あなたはそこに末尾のゼロコードのためにLUTを使って調子を取り除くことができます。
所属していません StackOverflow