计算奇偶校验

Posted

技术标签:

【中文标题】计算奇偶校验【英文标题】:Computing the Parity 【发布时间】:2013-06-25 09:53:48 【问题描述】:

我不完全理解这种位的算法。 谁能详细解释一下?

以下代码摘自《Hacker's Delight》一书:

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

【问题讨论】:

哪一部分你不明白? 移位和异或的顺序(加1的位数?) 【参考方案1】:

先说一点理论。

一组位的奇偶校验是 即使 1 位的数量是偶数,如果 1 位的个数是奇数。

我们将奇偶校验信息编码为:

1 --> 集合的奇偶性是奇数 0 --> 集合的奇偶校验是偶数

可以简单地计算一组两位的奇偶校验 使用 XOR:
b0 b1 --> P1-0
--------------
0 ^ 0 --> 0 --> 奇偶校验
0 ^ 1 --> 1 --> 奇偶校验
1 ^ 0 --> 1 --> 奇偶校验
1 ^ 1 --> 0 --> 奇偶校验
一组比特 S 的奇偶校验可以从两个不相交的子集 S1S2 的奇偶校验中计算出来,这样 S = S1 UNION S2 使用 XOR:P(S) = P(S1) ^ P(S2)。实际上: 如果S1S2 具有相同的奇偶性,即它们都有偶数位或奇数位,则它们的联合S 将具有偶数位。 如果S1S2 有不同的奇偶校验,S 将有奇数位。

现在我们可以理解这个技巧了,假设 unsigned int 有 32 位:它“递归”地计算奇偶校验,首先将两位(两个相邻位)的子集中的位分组,然后执行奇偶校验在那些子集上。然后它通过使用刚刚计算的 2 位子集的奇偶校验来检查下一个更大的 4 位集合的奇偶校验。然后继续使用 8 位和 16 位子集。

让我们以图形方式查看它(为了清楚起见,在最不重要的位上):

y = x ^ (x >> 1)

x: b7 b6 b5 b4 b3 b2 b1 b0 x>>1: b8 b7 b6 b5 b4 b3 b2 b1 y=: P8-7 P7-6 P6-5 P5-4 P4-3 P3-2 P2-1 P1-0

我使用符号Pn-m 表示位置从mn 的位集的奇偶性。由于我们必须使用不相交的子集计算奇偶校验,因此我们只使用其中两个奇偶校验值中的一个,我将用? 标记其他奇偶校验值,以表示它们没有意义。所以我们有:

是:? P7-6? P5-4 ? P3-2 ? P1-0

y = y ^ (y >> 2)(考虑更多高阶位)

是:P15-14? P13-12 ? P11-10 ? P9-8 ? P7-6? P5-4 ? P3-2 ? P1-0 y>>2: P17-16 ? P15-14 ? P13-12 ? P11-10 ? P9-8 ? P7-6? P5-4 ? P3-2 y=: P17-14 ? P15-12 ? P13-10 ? P11-8 ? P9-6? P7-4 ? P5-2 ? P3-0

再次,由于我们只需要不相交子集的奇偶性,我们忽略结果的一些位以避免重叠集合,即P5-2P9-6等,从而获得:

你:?? P15-12 ??? P11-8 ??? P7-4 ??? P3-0

y = y ^ (y >> 4)(考虑更多高阶位)

y: P23-20 ??? P19-16 ??? P15-12 ??? P11-8 ??? P7-4 ??? P3-0 y>>4: P27-24 ??? P23-20 ??? P19-16 ??? P15-12 ??? P11-8 ??? P7-4 y=: P27-20 ??? P23-16 ??? P19-12 ??? P15-8 ??? P11-4 ??? P7-0

再次,忽略重叠集(为了便于阅读,对 ?s 进行分组):

你:??? P23-16 ??? ??? P15-8 ??? ??? P7-0

y = y ^ (y >> 8)(考虑到所有 32 位):

是:P31-24 ??? ??? P23-16 ??? ??? P15-8 ??? ??? P7-0 y>>8: 0 000 0000 P31-24 ??? ??? P23-16 ??? ??? P15-8 y=: P31-24 ??? ??? P31-16 ??? ??? P23-8 ??? ??? P15-0

再次,忽略重叠集:

你:??? ??? P31-16 ??? ??? ??? ??? P15-0

y = y ^ (y >> 16)

你:??? ??? P31-16 ??? ??? ??? ??? P15-0 y>>16: 0000 0000 0 000 0000 ???? ??? P31-16 y=: ???? ??? P31-16 ??? ??? ??? ??? P31-0

return y & 1

你:??? ??? P31-16 ??? ??? ??? ??? P31-0 1:0000 0000 0 000 0000 0000 0000 1 y&1: 0000 0000 0 000 0000 0000 0000 P31-0

所以您可以看到返回的值只是参数x 的位的奇偶校验位P31-0,这正是我们想要的。

【讨论】:

【参考方案2】:

如果 x 只有 1 位,显然 ((x ^ (x >> 1)) & 1 会计算奇偶校验(只是将位相互异或)。

这种模式可以扩展到更多位。

如果你有 4 位,你会得到(至少,这是一种方法)

y = x ^ (x >> 1);
y = y ^ (y >> 2);
return y & 1;

这些位在哪里执行此操作:

x = a     b     c     d
y = a   a^b   b^c    c^d
y = a  a^b  a^b^c  a^b^c^d

如果将模式一直扩展到 32 位,则会得到问题中显示的代码。

【讨论】:

以上是关于计算奇偶校验的主要内容,如果未能解决你的问题,请参考以下文章

在Ruby中计算一个字节的奇偶校验

如何计算以下位序列的奇偶校验位?

计算奇偶校验

计算机组成原理——奇偶校验码

计算机组成原理——奇偶校验码

计算机网络:数据链路层——差错检验和纠错技术:奇偶校验和循环冗余校验