Reputation: 142
I saw this code called "Counting bits set, Brian Kernighan's way". I am puzzled as to how "bitwise and'ing" an integer with its decrement works to count set bits, can someone explain this?
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
}
Upvotes: 2
Views: 440
Reputation: 11557
Let A=an-1an-2...a1a0 be the number on which we want to count bits and k the index of the right most bit at one.
Hence A=an-1an-2...ak+1100...0=Ak+2k where Ak=an-1an-2...ak+1000...0
As 2k−1=000..0111..11, we have A-1=Ak+2k-1=an-1an-2...ak+1011...11
Now perform the bitwise & of A and A-1
an-1an-2...ak+1100...0 A
an-1an-2...ak+1011...1 A-1
an-1an-2...ak+1000...0 A&A-1=Ak
So A&A-1 is identical to A, except that its right most bit has been cleared, that proves the validity of the method.
Upvotes: 3
Reputation: 3677
Let's walk through the loop with an example : let's set v = 42
which is 0010 1010
in binary.
First iteration: c=0, v=42 (0010 1010)
.
Now v-1
is 41
which is 0010 1001
in binary.
Let's compute v & v-1
:
0010 1010
& 0010 1001
.........
0010 1000
Now v&v-1
's value is 0010 1000
in binary or 40 in decimal. This value is stored into v
.
Second iteration : c=1, v=40 (0010 1000)
. Now v-1
is 39
which is 0010 0111
in binary. Let's compute v & v-1
:
0010 1000
& 0010 0111
.........
0010 0000
Now v&v-1
's value is 0010 0000
which is 32
in decimal. This value is stored into v
.
Third iteration :c=2, v=32 (0010 0000)
. Now v-1
is 31
which is 0001 1111
in binary. Let's compute v & v-1
:
0010 0000
& 0001 1111
.........
0000 0000
Now v&v-1
's value is 0
.
c=3, v=0
. The loop terminates. c
contains 3
which is the number of bits set in 42
.You can see that the binary representation of v-1
sets the least significant bit or LSB (i.e. the rightmost bit that is a 1) from 1 to 0 and all the bits right of the LSB from 0 to 1.
When you do a bitwise AND between v
and v-1
, the bits left from the LSB are the same in v
and v-1
so the bitwise AND will leave them unchanged. All bits right of the LSB (including the LSB itself) are different and so the resulting bits will be 0.
In our original example of v=42 (0010 1010)
the LSB is the second bit from the right. You can see that v-1
has the same bits as 42
except the last two : the 0 became a 1 and the 1 became a 0.
Similarly for v=40 (0010 1000)
the LSB is the fourth bit from the right. When computing v-1 (0010 0111)
you can see that the left four bits remain unchanged while the right four bits became inverted (zeroes became ones and ones became zeroes).
The effect of v = v & v-1
is therefore to set the least significant bit of v
to 0 and leave the rest unchanged. When all bits have been cleared this way, v
is 0 and we have counted all bits.
Upvotes: 5
Reputation: 41200
Each time though the loop one bit is counted, and one bit is cleared (set to zero).
How this works is: when you subtract one from a number you change the least significant one bit to a zero, and the even less significant bits to one -- though that doesn't matter. It doesn't matter because they are zero in the values you're decrementing, so they will be zero after the and-operation anyway.
XXX1 => XXX0
XX10 => XX01
X100 => X011
etc.
Upvotes: 4