我在Stackoverflow上找到了一段代码,并根据需要对其进行了编辑。来源:How to check if value has even parity of bits or odd?
它就像一种魅力,但是我无法理解它为什么起作用。
我尝试将其写出,例如字节0b01101101。
01101101
00000110
-------- ^
01101011
00011010
-------- ^
01110001
00111000
-------- ^
01001001
虽然我的单元测试给出了答案; 1
uint8_t check_even_parity(uint8_t value){
value ^= value >> 4;
value ^= value >> 2;
value ^= value >> 1;
return value & 1;
}
预期为; 0 尝试写出时的实际结果; 01001001
答案 0 :(得分:2)
每个步骤组合两个比特集L和R,以使L的奇偶校验与R的奇偶校验合并。 R最终具有与L + R最初相同的奇偶校验。
在步骤1中,我们取8位,并产生一个与8位奇偶校验相同的4位数字。在第2步中,我们产生与4具有相同奇偶性的2位数字。在最后一步中,我们产生与2与2具有相同奇偶性的1位数字。这意味着在三步中,我们得到具有相同奇偶性的一位与原始8位相同。
让我告诉您一次意味着什么。
让我们从第一步开始,其中L是左4位(0110),R是右4位(1101)。
xxxx1101 (R)
xxxx0110 (L)
--------
xxxx1011 (R^L)
我已经前进了,对每个数字的左半部分进行x运算。这些位无关紧要。您将了解为什么,随着我们的前进:越来越少的位与每个步骤相关。
L是偶数,R是奇数,这意味着L + R是奇数。因此,R ^ = L应该使R具有奇校验。可以?的确如此。 0110有两个设置位,因此R ^ = 0110翻转R的两个位。翻转偶数位不会更改奇偶校验。 R保持奇数。
第二步,L是左2位(10),R是右2位(11)。
xxxxxx11 (R)
xxxxxx10 (L)
--------
xxxxxx01 (L^R)
现在将六位输出。我们只关心每个数字中的两位。
这次L是奇数,R是偶数。结合起来,L + R是奇数,因此这一次我们需要翻转R的奇偶校验。 R ^ = L可以吗?再次,确实如此。 L设置了奇数个位,因此对其进行异或运算将翻转R的奇数个位,从而确保R的奇偶校验被切换。 R变成奇数。
在最后一步中,L和R分别为1位。
xxxxxxx1 (L)
xxxxxxx0 (R)
--------
xxxxxxx1 (L^R)
L是1,R是0。就像前面的步骤一样,我们希望R ^ = L是奇数,并且是。 R为奇数。
很棒。我们从8位奇数奇偶校验开始,通过成功地将两个半部分合并在一起,我们得到了具有相同奇数奇偶校验的1位。
答案 1 :(得分:2)
我想提出一个可以提供一些直觉的隐喻:
想象一下,您面前有4张卡片,需要堆积。作为一个有两只手的人,您可以同时在每只手中拿起一张牌,并将它们放在另一只2顶上,然后拿起其中一对,再将其放在另一只上。
这会在2个步骤中堆放4张牌。
现在想象一下,您需要堆32张牌并拥有16手(或更多)。您可以使用相同的技术:创建16堆2张纸牌,而不是8堆4张纸牌,4堆8张纸牌,2堆16张纸牌,最后是32张纸牌。
这会在5个移动步骤中堆积32张卡片。
现在,根据处理器的能力,将“ pile”替换为“ xor”,将“ cards”替换为“ bits”,将“ hands”替换为“ p”。在5次移位和异或运算中,您将数字的32位异或在一起,如果该数字具有奇偶校验,则得到0,否则得到1。