查找C中的最高位

我所追求的东西是我可以input一个数字,它会返回最高位。 我确定有一个简单的方法。 下面是一个输出示例(左边是input)

  1  - > 1
 2  - > 2
 3  - > 2
 4  - > 4
 5  - > 4
 6  - > 4
 7  - > 4
 8  - > 8
 9  - > 8
 ...
 63  - > 32 

这应该做的伎俩。

int hob (int num) { if (!num) return 0; int ret = 1; while (num >>= 1) ret <<= 1; return ret; } 

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

从黑客的喜悦:

 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位或更高。

在许多体系结构中可以find硬件指令。 我怀疑这可能是最简单,最快速的做法。

 1<<(fls(input)-1) 

像混淆的代码? 尝试这个:

1 <<(int)log2(x)

现有的库调用可以很容易地解决这个问题。

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

Linux手册页给出了关于这个函数的更多细节,以及其他inputtypes的相应细节。

不断删除低位令人想到…

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

linux内核具有许多像这样的方便的bithop,为许多体系结构提供了最有效的编码方式。 您可以在include / asm-generic / bitops / fls.h (和朋友)中find通用版本,但是如果速度至关重要 ,可以参见include / asm-x86 / bitops.h以获得使用内联汇编的定义,而可移植性不。

一个快速的方法是通过查找表。 对于32位input和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; } 
 // 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 } 

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

对于这个派对来说晚了一点,但是我发现最简单的解决scheme就是将现代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); } 

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

我想出了一个漂亮的解决scheme是二进制search的位。

 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位。

为什么不简单地这样做:

 int HiBit(int num){ return (num & 0x80000000) >> 31; }