在C中找到最高位

我需要的是可以输入数字的东西,它将返回最高位。 我敢肯定有一个简单的方法。 下面是一个示例输出(左边是输入)

1 -> 1
2 -> 2
3 -> 2
4 -> 4
5 -> 4
6 -> 4
7 -> 4
8 -> 8
9 -> 8
...
63 -> 32
Harley Holcombe asked 2020-08-11T17:06:08Z
12个解决方案
83 votes

从黑客的喜悦:

int hibit(unsigned int n) {
    n |= (n >>  1);
    n |= (n >>  2);
    n |= (n >>  4);
    n |= (n >>  8);
    n |= (n >> 16);
    return n - (n >> 1);
}

该版本适用于32位整数,但逻辑可以扩展到64位或更高版本。

erickson answered 2020-08-11T17:06:52Z
38 votes

fls深入了解了许多体系结构上的硬件指令。 我怀疑这可能是最简单,最快的方法。

1<<(fls(input)-1)
Fabian answered 2020-08-11T17:07:12Z
30 votes

这应该可以解决问题。

int hob (int num)
{
    if (!num)
        return 0;

    int ret = 1;

    while (num >>= 1)
        ret <<= 1;

    return ret;
}

滚刀(1234)返回1024
滚刀(1024)返回1024
滚刀(1023)返回512

Kyle Cronin answered 2020-08-11T17:06:27Z
26 votes

像混淆代码? 试试这个:

1 <<(int)log2(x)

dmityugov answered 2020-08-11T17:07:37Z
5 votes

这可以通过现有的库调用轻松解决。

int highestBit(int v){
  return fls(v) << 1;
}

Linux手册页提供了有关此功能及其其他输入类型的更多详细信息。

dharga answered 2020-08-11T17:08:01Z
4 votes

不断想起低阶位...

int highest_order_bit( int x )
{
    int y = x;
    do { 
        x = y;
        y = x & (x-1); //remove low order bit
    }
    while( y != 0 );
    return x;
}
nlucaroni answered 2020-08-11T17:08:22Z
4 votes

一种快速的方法是通过查找表。 对于32位输入和8位查找表,只需要进行4次迭代即可:

int highest_order_bit(int x)
{
    static const int msb_lut[256] =
        {
            0, 0, 1, 1, 2, 2, 2, 2, // 0000_0000 - 0000_0111
            3, 3, 3, 3, 3, 3, 3, 3, // 0000_1000 - 0000_1111
            4, 4, 4, 4, 4, 4, 4, 4, // 0001_0000 - 0001_0111
            4, 4, 4, 4, 4, 4, 4, 4, // 0001_1000 - 0001_1111
            5, 5, 5, 5, 5, 5, 5, 5, // 0010_0000 - 0010_0111
            5, 5, 5, 5, 5, 5, 5, 5, // 0010_1000 - 0010_1111
            5, 5, 5, 5, 5, 5, 5, 5, // 0011_0000 - 0011_0111
            5, 5, 5, 5, 5, 5, 5, 5, // 0011_1000 - 0011_1111

            6, 6, 6, 6, 6, 6, 6, 6, // 0100_0000 - 0100_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0100_1000 - 0100_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0101_0000 - 0101_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0101_1000 - 0101_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0110_0000 - 0110_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0110_1000 - 0110_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0111_0000 - 0111_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0111_1000 - 0111_1111

            7, 7, 7, 7, 7, 7, 7, 7, // 1000_0000 - 1000_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1000_1000 - 1000_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1001_0000 - 1001_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1001_1000 - 1001_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1010_0000 - 1010_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1010_1000 - 1010_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1011_0000 - 1011_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1011_1000 - 1011_1111

            7, 7, 7, 7, 7, 7, 7, 7, // 1100_0000 - 1100_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1100_1000 - 1100_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1101_0000 - 1101_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1101_1000 - 1101_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1110_0000 - 1110_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1110_1000 - 1110_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1111_0000 - 1111_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1111_1000 - 1111_1111
        };

    int byte;
    int byte_cnt;

    for (byte_cnt = 3; byte_cnt >= 0; byte_cnt--)
    {
        byte = (x >> (byte_cnt * 8)) & 0xff;
        if (byte != 0)
        {
            return msb_lut[byte] + (byte_cnt * 8);
        }
    }

    return -1;
}
Ben Lever answered 2020-08-11T17:08:42Z
4 votes

linux内核具有许多这样的便捷位,它们以最有效的方式对许多体系结构进行了编码。 您可以在include / asm-generic / bitops / fls.h(和朋友)中找到通用版本,但如果速度至关重要,并且可移植性非常好,另请参见include / asm-x86 / bitops.h中使用内联汇编的定义。 不。

theorbtwo answered 2020-08-11T17:09:03Z
4 votes

这次聚会有点晚了,但是考虑到现代GCC作为编译器,我发现的最简单的解决方案就是:

static inline int_t get_msb32 (register unsigned int val)
{
  return 32 - __builtin_clz(val);
}

static inline int get_msb64 (register unsigned long long val)
{
  return 64 - __builtin_clzll(val);
}

它甚至是相对便携式的(至少它可以在任何GCC平台上运行)。

Kean answered 2020-08-11T17:09:28Z
2 votes
// Note doesn't cover the case of 0 (0 returns 1)
inline unsigned int hibit( unsigned int x )
{
  unsigned int log2Val = 0 ;
  while( x>>=1 ) log2Val++;  // eg x=63 (111111), log2Val=5
  return 1 << log2Val ; // finds 2^5=32
}
bobobobo answered 2020-08-11T17:09:44Z
2 votes

如果不需要便携式解决方案并且代码在x86兼容CPU上执行,则可以使用Microsoft Visual C / C ++编译器提供的_BitScanReverse()内在函数。 它映射到BSR CPU指令,该指令返回最高位。

Igor Levicki answered 2020-08-11T17:10:04Z
0 votes

我想到的一个不错的解决方案是对位进行二进制搜索。

uint64_t highestBit(uint64_t a, uint64_t bit_min, uint64_t bit_max, uint16_t bit_shift){
    if(a == 0) return 0;
    if(bit_min >= bit_max){
        if((a & bit_min) != 0)
            return bit_min;
        return 0;
    }
    uint64_t bit_mid = bit_max >> bit_shift;
    bit_shift >>= 1;
    if((a >= bit_mid) && (a < (bit_mid << 1)))
        return bit_mid;
    else if(a > bit_mid)
        return highestBit(a, bit_mid, bit_max, bit_shift);
    else
        return highestBit(a, bit_min, bit_mid, bit_shift);

}

最大位是2的最高幂,因此对于64位数字,它将是2 ^ 63。 位移应初始化为位数的一半,因此对于64位,它将是32。

Gavin Sellers answered 2020-08-11T17:10:29Z
translate from https://stackoverflow.com:/questions/53161/find-the-highest-order-bit-in-c