0

Here is the code that reports the bit parity of a given integer:

01: bool parity(unsigned int x)
02: {
03:   x ^= x >> 16;
04:   x ^= x >>  8;
05:   x ^= x >>  4;
06:   x &= 0x0F;
07:   return ((0x6996 >> x) & 1) != 0;
08: }

I found this here.. while there seems to be explanation in the link, I do not understand. The first explanation that start with The code first "merges" bits 0 − 15 with bits 16 − 31 using a right shift and XOR (line 3). is making it hard for me to understand as to what is going on. I tried to play around them but that did not help. if a clarity on how this work is given, it will be useful for beginners like me Thanks

EDIT: from post below:

value      : 1101 1110 1010 1101 1011 1110 1110 1111
value >> 16: 0000 0000 0000 0000 1101 1110 1010 1101
----------------------------------------------------
xor        : 1101 1110 1010 1101 0110 0001 0100 0010

now right shift this again by 8 bits:

value          : 1101 1110 1010 1101 0110 0001 0100 0010
value >>8      : 0000 0000 1101 1110 1010 1101 0110 0001
 ----------------------------------------------------
xor            : 1101 1110 1110 0001 0100 1100 0010 0011

so where is the merging of parity happening here?

eagertoLearn
  • 9,772
  • 23
  • 80
  • 122
  • Bit parity is simply XORing all the bits together. The above does it in "chunks" to make it faster and simpler, other than that last line which is definitely a bit weird. However, at that point the parity has been reduced to a 4-bit quantity in `x`, and so that last line is basically "looking up" the correct parity value for one of 16 possible values in `x` -- a clever, if obscure, short-cut. – Hot Licks Jan 03 '14 at 00:03

2 Answers2

4

Let's start first with a 2-bit example so you can see what's going on. The four possibilities are:

ab  a^b
--  ---
00   0
01   1
10   1
11   0

You can see that a^b (xor) gives 0 for an even number of one-bits and 1 for an odd number. This woks for 3-bit values as well:

abc  a^b^c
---  -----
000    0
001    1
010    1
011    0
100    1
101    0
110    0
111    1

The same trick is being used in lines 3 through 6 to merge all 32 bits into a single 4-bit value. Line 3 merges b31-16 with b15-0 to give a 16-bit value, then line 4 merges the resultant b15-b8 with b7-b0, then line 5 merges the resultant b7-b4 with b3-b0. Since b31-b4 (the upper half of each xor operation) aren't cleared by that operations, line 6 takes care of that by clearing them out (anding with binary 0000...1111 to clear all but the lower 4 bits).

The merging here is achieved in a chunking mode. By "chunking", I mean that it treats the value in reducing chunks rather than as individual bits, which allows it to efficiently reduce the value to a 4-bit size (it can do this because the xor operation is both associative and commutative). The alternative would be to perform seven xor operations on the nybbles rather than three. Or, in complexity analysis terms, O(log n) instead of O(n).

Say you have the value 0xdeadbeef, which is binary 1101 1110 1010 1101 1011 1110 1110 1111. The merging happens thus:

value      : 1101 1110 1010 1101 1011 1110 1110 1111
      >> 16: 0000 0000 0000 0000 1101 1110 1010 1101
----------------------------------------------------
xor        : .... .... .... .... 0110 0001 0100 0010

(with the irrelevant bits, those which will not be used in future, left as . characters).

For the complete operation:

value      : 1101 1110 1010 1101 1011 1110 1110 1111
      >> 16: 0000 0000 0000 0000 1101 1110 1010 1101
----------------------------------------------------
xor        : .... .... .... .... 0110 0001 0100 0010
      >>  8: .... .... .... .... 0000 0000 0110 0011
----------------------------------------------------
xor        : .... .... .... .... .... .... 0010 0001
      >>  4: .... .... .... .... .... .... 0000 0010
----------------------------------------------------
xor        : .... .... .... .... .... .... .... 0011

And, looking up 0011 in the table below, we see that it gives even parity (there are 24 1-bits in the original value). Changing just one bit in that original value (any bit, I've chosen the righmost bit) will result in the opposite case:

value      : 1101 1110 1010 1101 1011 1110 1110 1110
      >> 16: 0000 0000 0000 0000 1101 1110 1010 1101
----------------------------------------------------
xor        : .... .... .... .... 0110 0001 0100 0011
      >>  8: .... .... .... .... 0000 0000 0110 0011
----------------------------------------------------
xor        : .... .... .... .... .... .... 0010 0000
      >>  4: .... .... .... .... .... .... 0000 0010
----------------------------------------------------
xor        : .... .... .... .... .... .... .... 0010

And 0010 in the below table is odd parity.

The only "magic" there is the 0x6996 value which is shifted by the four-bit value to ensure the lower bit is set appropriately, then that bit is used to decide the parity. The reason 0x6996 (binary 0110 1001 1001 0110) is used is because of the nature of parity for binary values as shown in the lined page:

Val  Bnry  #1bits  parity (1=odd)
---  ----  ------  --------------
                         +------> 0x6996
                         |
  0  0000     0    even (0)
  1  0001     1    odd  (1)
  2  0010     1    odd  (1)
  3  0011     2    even (0)
  4  0100     1    odd  (1)
  5  0101     2    even (0)
  6  0110     2    even (0)
  7  0111     3    odd  (1)
  8  1000     1    odd  (1)
  9  1001     2    even (0)
 10  1010     2    even (0)
 11  1011     3    odd  (1)
 12  1100     2    even (0)
 13  1101     3    odd  (1)
 14  1110     3    odd  (1)
 15  1111     4    even (0)

Note that it's not necessary to do the final shift-of-a-constant. You could just as easily continue the merging operations until you get down to a single bit, then use that bit:

bool parity (unsigned int x) {
  x ^= x >> 16;
  x ^= x >>  8;
  x ^= x >>  4;
  x ^= x >>  2;
  x ^= x >>  1;
  return x & 1;
}

However, once you have the value 0...15, a shift of a constant by that value is likely to be faster than two extra shift-and-xor operations.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Q1: how does merging of 32 to 16 to 8 to 4 to 2 happens? can you briefly explain. I understood `XOR`ing even number of bits give zero and one otherwise – eagertoLearn Jan 03 '14 at 00:23
  • what happens in line 6? – eagertoLearn Jan 03 '14 at 00:32
  • @eagertoLearn: I've added further explanation of those two points which will hopefully make it clearer. – paxdiablo Jan 03 '14 at 00:35
  • you mentioned `zero/irrelevent bits left blank`. but when you right shift, you fill the `zeroes` on the right side, and when you `xor`, x and x>>16, the result will not be blank right? – eagertoLearn Jan 03 '14 at 00:36
  • @eagertoLearn, bad explanation on my part, I've cleaned it up. When you right shift, zero-bits are pushed in from the _left_ side, not the right. I'll also expand on the example all the way down to four bits. – paxdiablo Jan 03 '14 at 00:43
  • woow! great explanation. I kind of understood. Is there a typo here `And, looking up 0001` while it must `And, looking up 0011`. and why is the need to look up the table? can I just count the bits (it is two) and hence the `parity is even(0)` – eagertoLearn Jan 03 '14 at 00:51
  • again, this could be a stupid question, why stop with `0010` why not go all the way to two bits `10` and just count the `1 bits` – eagertoLearn Jan 03 '14 at 00:53
  • @eagertoLearn, good catch, I've fixed that value up. The final constant shift is simply a quick operation once you get down to a value you can shift the constant by safely (0...15). You _could_ count the 1-bits by continuing with `x ^ x >> 2; x ^= x >> 1;` but it's likely to be more inefficient. Updating the answer with that info as well. – paxdiablo Jan 03 '14 at 01:01
  • In the last method you wrote, you are not clearing `the first 31 bits` correct? I think it is not necessary to clear them anyway in this case. – eagertoLearn Jan 03 '14 at 01:04
  • @eagertoLearn: correct. You don't need to clear them in that case since you're only returning the lower bit anyway: `return x & 1;`. – paxdiablo Jan 03 '14 at 01:05
  • great! Thank you very much. one last question, here we are dealing with unsigned integers, are there any potential problems if I pass in negative numbers (they are signed at 32nd bit right) – eagertoLearn Jan 03 '14 at 01:06
  • Yes, there are potential problems. Right shifting of negative values is an implementation defined thing (C11 6.5.7/5) so may not work portably. Best to cast to unsigned either implicitly via the function prototype (as `parity()` does) or explicitly in the function call. – paxdiablo Jan 03 '14 at 01:12
  • may be I should rise a seperate question on bit parity for signed integers? – eagertoLearn Jan 03 '14 at 01:18
  • @eagertoLearn, you _could,_ but I wouldn't worry. That code will work fine with signed `int` values because they'll be cast to the unsigned variant by the prototype (possibly weird variations like one's complement and sign/magnitude encoding notwithstanding of course but they're so rare as to be irrelevant). But, it may also help out future visitors to the site so feel free to do so. – paxdiablo Jan 03 '14 at 01:22
2

From the original page,

Bit parity tells whether a given input contains an odd number of 1's.

So you want to add up the number of 1's. The code uses the xor operator to add pairs of bits,

0^1 = 1 bits on
1^0 = 1 bits on
0^0 = 0 bits on
1^1 = 0 bits on (well, 2, but we cast off 2's)

So the first three lines count up the number of 1's (tossing pairs of 1's).

That should help...

And notice from the original page, the description of why 0x6996,

If we encode even by 0 and odd by 1 beginning with parity(15) then we get 0110 1001 0110 1001 = 0x6996, which is the magic number found in line 7. The shift moves the relevant bit to bit 0. Then everything except for bit 0 is masked out. In the end, we get 0 for even and 1 for odd, exactly as desired.

ChuckCottrill
  • 4,360
  • 2
  • 24
  • 42