简体   繁体   English

在没有循环的情况下从C ++中的int中提取n个最重要的非零位

[英]Extract n most significant non-zero bits from int in C++ without loops

I want to extract the n most significant bits from an integer in C++ and convert those n bits to an integer. 我想从C ++中的整数中提取n个最高有效位,并将这n位转换为整数。

For example 例如

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

Now I want to extract the 4 most significant digits from that representation, ie 1111 现在我想从该表示中提取4个最高有效数字,即1111

00000000000000000000010010110000
                     ^^^^

and convert them again to an integer (1001 in decimal = 9). 并将它们再次转换为整数(十进制1001 = 9)。

How is possible with a simple c++ function without loops? 如何在没有循环的情况下使用简单的c ++函数?

Some processors have an instruction to count the leading binary zeros of an integer, and some compilers have instrinsics to allow you to use that instruction. 某些处理器具有计算整数的前导二进制零的指令,并且一些编译器具有允许您使用该指令的内在函数。 For example, using GCC: 例如,使用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;
}

For simplicity, I left out checks that the requested number of bits are available. 为简单起见,我省略了所请求的位数可用的检查。 For Microsoft's compiler, the intrinsic is called __lzcnt . 对于Microsoft的编译器,内在函数称为__lzcnt

If your compiler doesn't provide that intrinsic, and you processor doesn't have a suitable instruction, then one way to count the zeros quickly is with a binary search: 如果您的编译器没有提供该内在函数,并且您的处理器没有合适的指令,那么快速计算零的一种方法是使用二进制搜索:

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;
}

It's not fast, but (int)(log(x)/log(2) + .5) + 1 will tell you the position of the most significant non-zero bit. 它并不快,但(int)(log(x)/log(2) + .5) + 1会告诉你最重要的非零位的位置。 Finishing the algorithm from there is fairly straight-forward. 从那里完成算法是相当直接的。

This seems to work (done in C# with UInt32 then ported so apologies to Bjarne): 这似乎有效(在C#中用UInt32完成,然后移植到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;

I assumed you meant using only integer math. 我以为你的意思是只使用整数数学。

I used some code from @OliCharlesworth's link, you could remove the conditionals too by using the LUT for trailing zeroes code there. 我使用了@ OliCharlesworth链接中的一些代码,你也可以通过使用LUT在那里跟踪零代码来删除条件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM