5

C++ の整数から最上位 n ビットを抽出し、それらの n ビットを整数に変換したいと考えています。

例えば

int a=1200;
// its binary representation within 32 bit word-size is
// 00000000000000000000010010110000

ここで、その表現から最上位 4 桁、つまり 1111 を抽出したいと思います。

00000000000000000000010010110000
                     ^^^^

それらを再び整数に変換します (10 進数で 1001 = 9)。

ループのない単純な C++ 関数でどのように可能ですか?

4

3 に答える 3

7

一部のプロセッサには、整数の先頭のバイナリ ゼロをカウントする命令があり、一部のコンパイラには、その命令を使用できるようにする組み込み関数があります。たとえば、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;
}
于 2012-03-15T12:19:02.717 に答える
1

高速ではありませんが、(int)(log(x)/log(2) + .5) + 1ゼロ以外の最上位ビットの位置がわかります。そこからアルゴリズムを完成させるのはかなり簡単です。

于 2012-03-15T11:55:51.450 に答える
0

これは機能しているようです (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 を使用して、条件も削除できます。

于 2012-03-15T13:01:26.090 に答える