我正在尝试优化一些打包和解包例程。为了进行打包,我需要计算存储整数值所需的位数。这是当前的代码。
if (n == -1) return 32;
if (n == 0) return 1;
int r = 0;
while (n)
{
++r;
n >>= 1;
}
return r;
答案 0 :(得分:9)
非便携式,使用大多数现代架构上提供的位扫描反向操作码。它在Visual C ++中作为intrinsic公开。
Portly,问题中的代码不需要边缘案例处理。为什么需要一位存储0?无论如何,我会忽略问题的边缘。胆量可以有效地完成:
if (n >> 16) { r += 16; n >>= 16; }
if (n >> 8) { r += 8; n >>= 8; }
if (n >> 4) { r += 4; n >>= 4; }
if (n >> 2) { r += 2; n >>= 2; }
if (n - 1) ++r;
答案 1 :(得分:6)
您希望确定数字的整数对数基数2(l =最高位集)。 Sean Anderson的“Bit Twiddling Hacks”页面有几种方法,从循环中明显的计数位到使用表查找的版本。请注意,如果这种可移植性对您很重要,那么所演示的大多数方法都需要稍微修改才能使用64位整数。
只需确保在unsigned
版本的数字上进行任何用于计算最高位集的转换,因为编译器实现可能会或可能不签名扩展{{1对有符号值进行操作。
答案 2 :(得分:5)
你要做的是找到最重要的一点。有些架构只是为了这个目的而有一个特殊的指令。对于那些不这样做的人,请使用表查找方法。
创建一个包含256个条目的表,其中每个元素标识最高位。
循环遍历数字中的每个字节,或者使用一些if语句来查找最高阶非零字节。
我会让你从这里休息。
答案 3 :(得分:3)
你必须检查执行时间以确定粒度,但我的猜测是,一次做4位,然后一次恢复到一位会使它更快。日志操作可能比逻辑/位操作慢。
if (n < 0) return 32;
int r = 0;
while (n && 0x7FFFFFF0) {
r+=4;
n >>= 4; }
while (n) {
r++;
n >>= 1; }
return r;
答案 4 :(得分:3)
进行二分搜索而不是线性搜索。
if ((n >> 16) != 0)
{
r += 16;
n >>= 16;
}
if ((n >> 8) != 0)
{
r += 8;
n >>= 8;
}
if ((n >> 4) != 0)
{
r += 4;
n >>= 4;
}
// etc.
如果您的硬件具有位扫描反转,则更快的方法是用汇编语言编写例程。为了保持代码的可移植性,你可以做到
#ifdef ARCHITECTURE_WITH_BSR
asm // ...
#else
// Use the approach shown above
#endif
答案 5 :(得分:1)
number_of_bits = log2(integer_number)
四舍五入到更高的整数。