0

这是报告bit parity给定整数的代码:

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: }

我在这里找到了这个。. 虽然链接中似乎有解释,但我不明白。开始的第一个解释The code first "merges" bits 0 − 15 with bits 16 − 31 using a right shift and XOR (line 3).是让我很难理解发生了什么。我试图在他们周围玩耍,但这没有帮助。如果清楚地说明这项工作的方式,它将对像我这样的初学者有用谢谢

编辑:来自下面的帖子:

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

现在再次右移 8 位:

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

那么奇偶校验的合并发生在哪里呢?

4

2 回答 2

4

让我们首先从一个 2 位示例开始,以便您了解发生了什么。四种可能是:

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

您可以看到,a^b (xor)对于偶数个位给出 0,对于奇数给出 1。这也适用于 3 位值:

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

第 3 行到第 6 行使用了相同的技巧,将所有 32 位合并为一个 4 位值。第 3 行与 合并b31-16b15-0给出 16 位值,然后第 4 行将结果b15-b8b7-b0合并,然后第 5 行将结果b7-b4与合并b3-b0。由于b31-b4(每个异或操作的上半部分)没有被该操作清除,第 6 行通过清除它们来解决这个问题(并使用二进制0000...1111清除除低 4 位之外的所有位)。

这里的合并是在分块模式下实现的。通过“分块”,我的意思是它将值减少块而不是单个位,这允许它有效地将值减小到 4 位大小(它可以这样做,因为 xor 操作既是关联的又是可交换的) . 另一种方法是对 nybbles 执行七次异或运算,而不是三个。或者,在复杂性分析术语中,O(log n) 而不是 O(n)。

假设你有值0xdeadbeef,它是二进制的1101 1110 1010 1101 1011 1110 1110 1111。合并是这样发生的:

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

(与不相关的位,将来不会使用的位,保留为.字符)。

对于完整的操作:

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

而且,查看0011下表,我们看到它给出了偶校验(原始值中有 24 个 1 位)。仅更改原始值中的一位(任何位,我选择了最右边的位)将导致相反的情况:

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

0010在下表中是奇校验。

唯一的“魔术”是0x6996通过四位值移位的值以确保正确设置低位,然后位用于确定奇偶校验。0x6996使用(binary )的原因0110 1001 1001 0110是因为二进制值的奇偶校验性质,如划线页所示:

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)

请注意,没有必要进行最后的常数移位。你可以很容易地继续合并操作,直到你得到一个位,然后使用那个位:

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

但是,一旦有了 value 0...15,将一个常数移位该值可能比两个额外的 shift-and-xor 操作更快。

于 2014-01-03T00:04:22.947 回答
2

从原始页面,

位奇偶校验告诉给定输入是否包含奇数个 1。

所以你想把 1 的个数加起来。该代码使用 xor 运算符来添加位对,

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)

所以前三行计算了 1 的数量(投掷一对 1)。

那应该有帮助...

并从原始页面中注意到,为什么 0x6996 的描述,

如果我们从 parity(15) 开始以 0 和 1 进行奇数编码,那么我们得到 0110 1001 0110 1001 = 0x6996,这是在第 7 行中找到的幻数。移位将相关位移动到位 0。然后除了位 0 被屏蔽。最后,我们得到 0 表示偶数,1 表示奇数,完全符合我们的要求。

于 2014-01-03T00:05:54.097 回答