【发布时间】:2014-03-07 16:09:17
【问题描述】:
假设 X 是一个无符号整数,我将如何从 X 中提取第 5 位并返回 X 中 1 的数量。注意:这两个操作不相互依赖。
为了从 X 中提取第 5 位,我想使用 & 操作来做这样的事情:XXXX1X & 000010
我不太确定如何返回 X 中 1 的位数。
谢谢!
【问题讨论】:
标签: c bit-manipulation
假设 X 是一个无符号整数,我将如何从 X 中提取第 5 位并返回 X 中 1 的数量。注意:这两个操作不相互依赖。
为了从 X 中提取第 5 位,我想使用 & 操作来做这样的事情:XXXX1X & 000010
我不太确定如何返回 X 中 1 的位数。
谢谢!
【问题讨论】:
标签: c bit-manipulation
计算 1 位的数量相对简单;您遍历数字的所有位并将设置的位数添加到一些累加器中:
unsigned int X;
unsigned int count;
for (count = 0; X; X >>= 1) {
count += X & 1;
}
它是如何工作的:
提取第 5 位也很简单,只需将数字 X 右移 5 并用 1 计算逻辑与:
unsigned int fifthBit (unsigned int X) {
return (X >> 5) & 1;
}
【讨论】:
X & (1 << 5)。我只是选择使用右移。
(X >> n) & 1 可以用更少或更小的指令进行编码,因为它使用 immediates 而不是将常量加载到寄存器中。它也适用于几乎所有类型,因为 (1 << N) & uint64_t 在 32 位架构中无法按计划工作。
在int 中查找设置位数的更短更简单的方法如下:
int num_1_bits(unsigned int x) // or unsigned long x; or unsigned short x;
{
int bitcount = 0;
while(x)
{
x &= (x - 1);
++bitcount;
}
return bitcount;
}
这是如何工作的?
对于无符号数x,x - 1 中的位序列将是x 的补码,直到x 的第一个设置位从 LSB 计数。
即对于x = 20 [0b11100]; x - 1 = 19 [0b11011]
这里19 的位序列是20 的补码,直到20 中的第一个设置位(LSB 位置3 的第一个设置位)。
因此,
如果您执行x & (x - 1),此操作将消耗来自x 的一个设置位。
因此,
如果您想继续这样做直到x 变为0,您将需要执行与x 中的设置位一样多的次数,这反过来将为您提供x 中设置位的计数.
这种方法更好,因为循环只会运行与x 中的1 位一样多的次数,因此不依赖于x 的数据类型。
【讨论】:
作为补充,我确切地说,如果您正在寻找效率,那么有一些内置的硬件指令可以对位执行计算(计数零:您可以推断出您有多少 1-bit)参见 article举个例子。
【讨论】: