How do I count the number of zero bits in an integer?

前端 未结 12 2108
梦谈多话
梦谈多话 2021-02-02 00:25

How would i go about finding the number of \'zero\' bits in C++. Suppose I have an integer;

int value = 276; 

For which I have the bits 100010

相关标签:
12条回答
  • 2021-02-02 00:38

    The easiest most naive way is to just iterate over the bits and count:

    size_t num_zeroes = 0;
    
    for(size_t i = 0; i < CHAR_BIT * sizeof value; ++i)
    {
      if ((value & (1 << i)) == 0)
        ++num_zeroes;
    }
    

    There are all number of better (for different values of "better") ways, but this is quite clear, very terse (code-wise), and doesn't require a bunch of setup.

    One micro-optimization that might be considered an improvement is to not compute the mask to test each bit, instead shift the value and always test the rightmost bit:

    for(size_t i = 0; i < CHAR_BIT * sizeof value; ++i, value >>= 1)
    {
      if ((value & 1) == 0)
        ++num_zeroes;
    }
    
    0 讨论(0)
  • 2021-02-02 00:39

    I'm surprised no one has mentioned this one:

    int num_zero_bits = __builtin_popcount(~num);
    

    This will give the number of zero bits in num when used with GCC.

    0 讨论(0)
  • 2021-02-02 00:42

    Expanding on ronag's answer, which other users have mentioned leads to wrong results (his algorithm works only up to a value of x = 15), here is an updated version of the algorithm:

    uint8_t count_1bits(uint32_t x) {
        x = x - ((x >> 1) & 0x55555555);
        x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
        x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
        x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
        x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF);
        return x & 0x3F;
    }
    
    uint8_t count_0bits(uint32_t x)    {
        return 32 - count_1bits(x);
    }
    

    The explanation of the first line from ronag is correct, however, the remaining lines are using a different approach. In the first line, through the shifting and subtracting, each 2-bit pair will contain the number of bits that were set in that pair in the original number. The rest of the lines recursively fold those numbers together by adding the lsb of each 2n-bit group to the msb of that pair shifted by n, so that the 2n-bit group contains the number of bits that was set in that group in the original number:

    01110110: 0111 (7 bits were set in the original number) 0110 (6 bits were set in the original number)
    -> 01110110 & 00001111 + (01110110 >> 4) & 00001111
    = 0110 + 0111
    = 1101
    

    The above algorithm works for 32 bit integers, but can easily be adapted by changing the constants to the correct bit-length so that the pattern stays the same (e.g. 0x5555... = 0101..., 0x0f0f... = 00001111... etc.) and adding/removing the appropriate shifts

    0 讨论(0)
  • 2021-02-02 00:45

    Kernighan way of counting set bits

    unsigned int v; // count the number of bits set in v
    unsigned int c; // c accumulates the total bits set in v
    for (c = 0; v; c++)
    {
      v &= v - 1; // clear the least significant bit set
    }
    

    Can be easily adapted for the task given. A number of iterations here is equal to a number of bits set.

    I also recommend the link above for various other ways of solving this and others types of bit-related tasks. There also is a single line example of obtaining bit count implemented in macros.

    0 讨论(0)
  • 2021-02-02 00:46

    You can do 32 minus the number of bits set.

    0 讨论(0)
  • 2021-02-02 00:47

    If you want efficiency then there is a good implementation in the book "Hackers Delight"

    22 instructions branch free.

    unsigned int count_1bits(unsigned int x)
    {
        x = x - ((x >> 1) & 0x55555555);
        x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
        x = x + (x >> 8);
        x = x + (x >> 16);
        return x & 0x0000003F;
    }
    
    unsigned int count_0bits(unsigned int x)
    {
        return 32 - count_1bits(x);
    }
    

    I'll try to explain how it works. It is a divide-and-conquer algorithm.

    (x >> 1) & 0x55555555
    

    Shifts all bits 1 step to the right and takes the least significant bit of every bit pair.

    0x55555555 -> 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 (16x2 bit pairs)
    

    So basically you will have the following table of all 2 bit permutations.

    1. (00 >> 1) & 01 = 00
    2. (01 >> 1) & 01 = 00
    3. (10 >> 1) & 01 = 01
    4. (11 >> 1) & 01 = 01
    
    x - ((x >> 1) & 0x55555555);
    

    Then you subtract these from the non shifted pairs.

    1. 00 - 00 = 00 => 0 x 1 bits
    2. 01 - 00 = 01 => 1 x 1 bits
    3. 10 - 01 = 01 => 1 x 1 bits
    4. 11 - 01 = 10 => 2 x 1 bits
    
    x = x - ((x >> 1) & 0x55555555);
    

    So now we have changed every 2 bit pair so that their value is now the number of bits of their corresponding original 2 bit pairs... and then we continue in similar way with 4 bit groups, 8 bit groups, 16 bit groups and final 32 bit.

    If you want a better explanation buy the book, there are a lot of good explanation and discussions of alternative algorithms etc...

    0 讨论(0)
提交回复
热议问题