轻松理解CRC差错检测算法七 -注解

来源:互联网 发布:二合一笔记本 知乎 编辑:程序博客网 时间:2024/05/08 15:02

原文第9部分的补充

原因

不得不承认把这个系列的翻译继续下去是很有挑战的。最近加班多,工作之余的精力就比较少了。坚持下去的想法还是有的,但回顾渐忘的初心,做这件事情的意义是在于帮助那些想把CRC算法学明白,而英文又差那么一点的人们,帮助他们从最根本的原理上来理解这个算法系列。我在之前自己看的过程中就发现作者的思路时有跳跃性。我自己在看的时候思路经常出现断续,作者说的标题“轻松理解”其实是有点夸大了。不符合我的习惯,我的习惯是每一个演进,都有它的原理在里面,可以直接看到,不需要读者再去思考。所以有了写这篇注解动机。
为了保持译文的完整和原本的条理,不方便直接在原文中加入大量的注解,另外只有证明我自己确实是理解了这部分,才能说明我翻译的基础是牢固的。所以才有了这一篇,作为原文第9节的注解。这里我会把我理解这部分的思路一步步展现出来。

原文梳理

第9节作为第8节的进一步,远远没有第8节那么容易理解。第8节,在讲解基本的直接实现的算法,其原理也非常简单,与长除法对应,也就是用移位与异或来实现长除法。第9节中,在第8节直接实现的基础上,作者介绍了表驱动实现。他的思路是,介绍表驱动的2个基础理论

1. 由poly和信息的前8位,可以确定第8次迭代后,寄存器的最高位值是0或者1。
2. 一个特定数a多次在不同的偏移位置与同一数b相异或,得到的结果,与a经过相同的偏移的值相异或后,再与b相异或得到的结果相同。用公式表达就是:
[(a << 1) ^ b] ^ a ^ (a << 2) ^ (a << n) =
[(a << 1) ^ a ^ (a << 2) ^ (a << n)] ^ b
有了这样的两个条件后,然后实然一下,作者不厚道地把表驱动实现的伪代码摆了出来。这里的跳跃性太大了,相信许多原文的人都没有搞明白。我要做的就是把这部分空白补上。

填补空白

填补之前,我们还是把思路再前移动一个环节看下,为什么长除法可以用移位+异或来实现。这样我们的思路就前后衔接,完美无瑕。
这个图中展示出的是长除法的计算过程。用伪代码来描述就是:
1. 把W位除数与被除数左对齐。
2. 如果被除数不小于除数,即被除数最高位是1,执行第3步。否则执行第4步。
3. 执行与除数的CRC减法(异或)运算。得到一个差值,这个差值长度一定比除数要短1,即W-1。跳到第5步。
4. 把除数全部位设0,执行CRC减法运算,自右向左保留W-1位。跳到第5步。
5. 如果被除数后面还有数位,则在差值尾部补上被除数的下一位,跳到第2步。否则运算结束,得到的最后差,即为余数。
这里写图片描述
这个算法是如何变为直接实现算法呢?
其实不难看出,在上述算法中,第2步中的判断就是关键。我们知道一个好的poly的首位肯定是1。所以要看是否执行异或操作,全看当前与poly对齐时,被除数的最高位是否是1。是1则相异或,0则不异或。

那么为什么poly比寄存器要宽1位呢?在长除法的例子中,可以看到与poly对齐时,除数最高位无论是0,还是1,在下次运算中,它都会被抛弃,因为如果1,它与poly相异或得到的是0,如果是0,则与全0异或时得到的还是0。也就是说,无论什么情况下,它都会变成0。
这里写图片描述
香农-布朗信息论告诉我们,一个事件的信息量与它发生的概率的对数值成反比,即越可能发生的事情其信息量就越小,必然发生的事情,其信息量就是0了。没有信息量,在信息时代就没有用处了。没有用处,就不需要留下它了。
第9节中提到的两个基础理论,应该很容易理解。我关注的是如何把它们过渡到表驱动实现。
表驱动中,信息的处理单元是字节。直接实现中处理的信息单元是位。
由于我们关心的是最后余数,也就是信息处理完成后,留在寄存器里的值。中间过程中会发生什么,中间寄存器的值会变成什么,我们并不关心,只要它的值可以传递到最后,参与最后一次异或运算即可。如果没有这个作为跳板,很难明白,为什么可以把位单元操作,变换为字节单元的操作。按照这个目的作为指引。我们看下,结构长除法的例子,看下在运算过程中到底发生了什么。
例子中,除数的位宽为5。那么来看下前5次运算。用R代表寄存器,p代表除数。
R ^ p ^ (p >> 1) ^ 0 ^ 0
得到的余数是01011。没错这就是我们关心的,前5次运算后,寄存器中的值,正是它将直接参与到下个字节中的运算中。
按照前面提到的第2个基础,这5次运算可以看作是如下,方便后面引用写作R ^ X:
R ^ (p ^ (p >> 1) ^ 0 ^ 0) = R ^ X
OK,这里就可以看出为什么这5次运算可以合并为1次 。首先R中的值只会有2^5种可能,也就是0到31。这个情况是可以提前知道的,也是必然的。由于p是提前也知道的,那么与每一个R值对应的前5次的运算是确切可以知道的,也就是X的值是可以提前知道的。X的值就是我们要在表格里索引的值。也就实现了一次处理5个位的信息了。
前5个位处理完成后,X与其后信息组成一个新的信息列,重复取前5个来索引得到后面的新余数,最终完成整个表驱动算法。
看到这里,相信每个人都已经明白了。:-)

0 0
原创粉丝点击