Reputation: 235
I've found a piece of code on Stackoverflow and edited it to my needs. source: How to check if value has even parity of bits or odd?
It works like a charm, but I can't get my head around WHY it works.
I tried writing it out, with example byte 0b01101101.
01101101
00000110
-------- ^
01101011
00011010
-------- ^
01110001
00111000
-------- ^
01001001
While my unit test gives the answer; 1
uint8_t check_even_parity(uint8_t value){
value ^= value >> 4;
value ^= value >> 2;
value ^= value >> 1;
return value & 1;
}
Expected is; 0 Actual result when trying to write it out; 01001001
Upvotes: 1
Views: 2225
Reputation: 1
byte parity_even_bit(byte val)
{
for(int i=1;i<8;i++)
{
val ^= ((val >> i) & 0x01);
}
return (val &= 0x01);
}
Upvotes: -1
Reputation: 300
I would like to propose a metaphor that may give some intuition:
Imagine you have 4 cards lying in front of you, which you need to pile up. As a person with 2 hands, you can pick up a card in each hand simultaneously and place them on top of the other 2, then pick up one of the pairs and put it on top of the other.
This piles 4 cards in 2 moves.
Now imagine you need to pile 32 cards and have 16 hands (or more). You can use the same technique: create 16 piles of 2 cards, than 8 piles of 4 cards, 4 piles of 8 cards, 2 piles of 16 cards and finally a single pile of 32 cards.
This piles 32 cards in 5 moves.
Now replace 'pile' with 'xor', 'cards' with 'bits' and 'hands' with the capability of the processor. In 5 shifts and xors, you get the 32 bits of a number xor-ed together, which gives you 0 if the number have even parity and 1 otherwise.
Upvotes: 2
Reputation: 361605
Each step combines two bitsets L and R such that L's parity is merged with R's. R ends up having the same parity as L+R did originally.
In step 1 we take 8 bits and produce a 4-bit number with the same parity as the 8-bit one. In step 2 we produce a 2-bit number with the same parity as the 4. In the last step we produce a 1-bit number with the same parity as the 2. That means in three steps we get a single bit with the same parity as the original 8.
Let me show you what I mean one step at a time.
Let's start with the first step where L is the left 4 bits (0110) and R is the right 4 (1101).
xxxx1101 (R)
xxxx0110 (L)
--------
xxxx1011 (R^L)
I've gone ahead and x'ed out the left half of each number. Those bits don't matter. You'll see why as we progress: fewer and fewer bits will be relevant each step.
L is even and R is odd, which means L+R is odd. R ^= L should therefore leave R with odd parity. Does it? It does indeed. 0110 has two set bits, so R ^= 0110 flips two of R's bits. Flipping an even number of bits won't change parity. R remains odd.
In the second step, L is the left 2 bits (10) and R is the right 2 (11).
xxxxxx11 (R)
xxxxxx10 (L)
--------
xxxxxx01 (L^R)
Now six bits are x'ed out. We're only concerned with two bits from each number.
This time L is odd and R is even. Combined, L+R is odd, so this time we need to flip R's parity. Does R ^= L do that? Again, it does. L has an odd number of bits set, so XORing it will flip an odd number of bits of R, guaranteeing that R's parity is switched. R becomes odd.
In the final step, L and R are just 1 bit apiece.
xxxxxxx1 (L)
xxxxxxx0 (R)
--------
xxxxxxx1 (L^R)
L is 1, R is 0. Just like in the previous steps, we're hoping that R ^= L is odd, and it is. R is odd.
Wonderful. We started with 8 bits with odd parity and by successfully merging two halves together we got down to 1 bit with the same odd parity.
Upvotes: 2