在二进制数中查找尾随0

时间:2011-10-18 18:40:11

标签: c binary

如何在二进制数中找到尾随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++;
      }

我想回顾一下这种方法。

8 个答案:

答案 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)。你每次检查最后一个数字,如果它是零,你丢弃它的尾随零位数的增量。

我认为对于尾随零,你不需要循环。

请考虑以下事项:

  • 如果减去1,数字(当然是二进制表示)会发生什么?哪个数字更改,哪个保持不变?
  • 如何组合原始数字和减少版本,以便只留下代表尾随零的位?

如果您正确应用上述步骤,您可以找到以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);
}

但要小心,因为你看到有两个问题:

  1. 此函数是为64位整数定义的。 (您可以将其用于某些演员表)
  2. 对于0值,您必须定义默认值。 (例如0-1
  3. 我认为这些问题是可以接受的。

答案 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即可获得尾随零的数量。