如何在二进制数中找到尾随0的数量?基于K& R bitcount在二进制数中找到1的示例我修改了一下以找到尾随的0。
int bitcount(unsigned x)
{
int b;
for(b=0;x!=0;x>>=1)
{
if(x&01)
break;
else
b++;
}
我想回顾一下这种方法。
答案 0 :(得分:6)
这是一种并行计算计数以提高效率的方法:
unsigned int v; // 32-bit word input to count zero bits on right
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -signed(v);
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
答案 1 :(得分:4)
在X86平台上的GCC上,您可以使用__builtin_ctz(no)
在用于X86的Microsoft编译器上,您可以使用_BitScanForward
他们都发出bsf指令
答案 2 :(得分:3)
另一种方法(我很惊讶,这里没有提到)将构建一个包含256个整数的表,其中数组中的每个元素都是该索引的最低1位。然后,对于整数中的每个字节,您将在表中查找。
这样的事情(我没有花时间调整这个,这只是为了粗略地说明这个想法):
int bitcount(unsigned x)
{
static const unsigned char table[256] = { /* TODO: populate with constants */ };
for (int i=0; i<sizeof(x); ++i, x >>= 8)
{
unsigned char r = table[x & 0xff];
if (r)
return r + i*8; // Found a 1...
}
// All zeroes...
return sizeof(x)*8;
}
对于像这样的问题的一些表驱动方法的想法是if
语句在分支预测方面花费了你一些东西,所以你应该旨在减少它们。它还减少了位移的数量。您的方法执行if
语句和每位移位,并且每个字节执行一次。 (希望优化器可以展开for循环,而不是为此发出比较/跳转。)其他一些答案的语句比if
语句更少,但表格方法简单易懂。当然,您应该以实际测量为指导,看看是否有任何重要因素。
答案 3 :(得分:0)
应该是:
int bitcount(unsigned char x)
{
int b;
for(b=0; b<7; x>>=1)
{
if(x&1)
break;
else
b++;
}
return b;
}
甚至
int bitcount(unsigned char x)
{
int b;
for(b=0; b<7 && !(x&1); x>>=1) b++;
return b;
}
甚至(yay!)
int bitcount(unsigned char x)
{
int b;
for(b=0; b<7 && !(x&1); b++) x>>=1;
return b;
}
或......
啊,不管怎样,there are 100500 millions methods of doing this。使用你需要的任何东西。
答案 4 :(得分:0)
我认为您的方法有效(尽管您可能希望使用unsigned int
)。你每次检查最后一个数字,如果它是零,你丢弃它的尾随零位数的增量。
我认为对于尾随零,你不需要循环。
请考虑以下事项:
如果您正确应用上述步骤,您可以找到以O(lg n)步骤设置的最高位(如果您对如何操作感兴趣,请查看here。)
答案 5 :(得分:0)
我有快速和高效功能:
int bitcount(unsigned __int64 value)
{
if (!value)
return SOME_DEFAULT_VALUE;
value &= -value;
unsigned int lsb = (unsigned) value | (unsigned) (value >> 32);
return (int)(((((((((((unsigned) (value >> 32) != 0) * 2)
+ ((lsb & 0xffff0000) != 0)) * 2)
+ ((lsb & 0xff00ff00) != 0)) * 2)
+ ((lsb & 0xf0f0f0f0) != 0)) * 2)
+ ((lsb & 0xcccccccc) != 0)) * 2)
+ ((lsb & 0xaaaaaaaa) != 0);
}
但要小心,因为你看到有两个问题:
0
值,您必须定义默认值。 (例如0
或-1
) 我认为这些问题是可以接受的。
答案 6 :(得分:0)
我们可以使用位操作轻松获取它,我们不需要遍历所有位。伪代码:
int bitcount(unsigned x) {
int xor = x ^ (x-1); // this will have (1 + #trailing 0s) trailing 1s
return log(i & xor); // i & xor will have only one bit 1 and its log should give the exact number of zeroes
}
答案 7 :(得分:0)
int countTrailZero(unsigned x) {
if (x == 0) return DEFAULT_VALUE_YOU_NEED;
return log2 (x & -x);
}
说明:
x&amp; -x返回用1设置的最右位数。
e.g。 6 - &gt; “0000,0110”,(6&amp; -6) - &gt; “0000,0010”
你可以通过两个补充来减去这个: x =“a1b”,其中b表示所有尾随零。 那么
-x = !(x) + 1 = !(a1b) + 1 = (!a)0(!b) + 1 = (!a)0(1...1) + 1 = (!a)1(0...0) = (!a)1b
所以
x & (-x) = (a1b) & (!a)1b = (0...0)1(0...0)
只需执行log2即可获得尾随零的数量。