循环冗余检验 (CRC) 算法原理

转载

https://www.cnblogs.com/esestt/archive/2007/08/09/848856.html


Cyclic Redundancy Check循环冗余检验,是基于数据计算一组效验码,用于核对数据传输过程中是否被更改或传输错误。

算法原理

假设数据传输过程中需要发送15位的二进制信息g=101001110100001,这串二进制码可表示为代数多项式g(x) = x^14 + x^12 + x^9 + x^8 + x^7 + x^5 + 1,其中g中第k位的值,对应g(x)中x^k的系数。将g(x)乘以x^m,既将g后加m个0,然后除以m阶多项式h(x),得到的(m-1)阶余项r(x)对应的二进制码r就是CRC编码。

h(x)可以自由选择或者使用国际通行标准,一般按照h(x)的阶数m,将CRC算法称为CRC-m,比如CRC-32、CRC-64等。国际通行标准可以参看http://en.wikipedia.org/wiki/Cyclic_redundancy_check

g(x)和h(x)的除运算,可以通过g和h做xor(异或)运算。比如将11001与10101做xor运算:

      

明白了xor运算法则后,举一个例子使用CRC-8算法求101001110100001的效验码。CRC-8标准的h(x) = x^8 + x^7 + x^6 + x^4 + x^2 + 1,既h是9位的二进制串111010101。 

      

经过迭代运算后,最终得到的r是10001100,这就是CRC效验码。

通过示例,可以发现一些规律,依据这些规律调整算法:

1. 每次迭代,根据gk的首位决定b,b是与gk进行运算的二进制码。若gk的首位是1,则b=h;若gk的首位是0,则b=0,或者跳过此次迭代,上面的例子中就是碰到0后直接跳到后面的非零位。

               


2. 每次迭代,gk的首位将会被移出,所以只需考虑第2位后计算即可。这样就可以舍弃h的首位,将b取h的后m位。比如CRC-8的h是111010101,b只需是11010101。 

      

3. 每次迭代,受到影响的是gk的前m位,所以构建一个m位的寄存器S,此寄存器储存gk的前m位。每次迭代计算前先将S的首位抛弃,将寄存器左移一位,同时将g的后一位加入寄存器。若使用此种方法,计算步骤如下: 

      

※蓝色表示寄存器S的首位,是需要移出的,b根据S的首位选择0或者h。黄色是需要移入寄存器的位。S'是经过位移后的S。

 

查表法

同样是上面的那个例子,将数据按每4位组成1个block,这样g就被分成6个block。

      

下面的表展示了4次迭代计算步骤,灰色背景的位是保存在寄存器中的。 

      

经4次迭代,B1被移出寄存器。被移出的部分,不我们关心的,我们关心的是这4次迭代对B2和B3产生了什么影响。注意表中红色的部分,先作如下定义:

   B23 = 00111010
   b1 = 00000000
   b2 = 01010100
   b3 = 10101010
   b4 = 11010101
   b' = b1 xor b2 xor b3 xor b4

4次迭代对B2和B3来说,实际上就是让它们与b1,b2,b3,b4做了xor计算,既:

   B23 xor b1 xor b2 xor b3 xor b4

可以证明xor运算满足交换律和结合律,于是:

   B23 xor b1 xor b2 xor b3 xor b4 = B23 xor (b1 xor b2 xor b3 xor b4) = B23 xor b'

b1是由B1的第1位决定的,b2是由B1迭代1次后的第2位决定(既是由B1的第1和第2位决定),同理,b3和b4都是由B1决定。通过B1就可以计算出b'。另外,B1由4位组成,其一共2^4有种可能值。于是我们就可以想到一种更快捷的算法,事先将b'所有可能的值,16个值可以看成一个表;这样就可以不必进行那4次迭代,而是用B1查表得到b'值,将B1移出,B3移入,与b'计算,然后是下一次迭代。

      

可看到每次迭代,寄存器中的数据以4位为单位移入和移出,关键是通过寄存器前4位查表获得
,这样的算法可以大大提高运算速度。

上面的方法是半字节查表法,另外还有单字节和双字节查表法,原理都是一样的——事先计算出2^8或2^16个b'的可能值,迭代中使用寄存器前8位或16位查表获得b'。

反向算法

之前讨论的算法可以称为正向CRC算法,意思是将g左边的位看作是高位,右边的位看作低位。G的右边加m个0,然后迭代计算是从高位开始,逐步将低位加入到寄存器中。在实际的数据传送过程中,是一边接收数据,一边计算CRC码,正向算法将新接收的数据看作低位。

逆向算法顾名思义就是将左边的数据看作低位,右边的数据看作高位。这样的话需要在g的左边加m个0,h也要逆向,例如正向CRC-16算法h=0x4c11db8,逆向CRC-16算法h=0xedb88320。b的选择0还是h,由寄存器中右边第1位决定,而不是左边第1位。寄存器仍旧是向左位移,就是说迭代变成从低位到高位。

好文要顶 关注我 收藏该文
Cheney Shue
关注 - 0
粉丝 - 105
+加关注
4
0
« 上一篇: 欲使用SharePoint开发检验数据管理系统,寻求帮助,熟悉SPS SDK的请来看看
» 下一篇: [日志]08/19/2007
posted on 2007-08-09 10:37 Cheney Shue 阅读( 54563) 评论( 22) 编辑 收藏

评论

#1楼 2007-09-17 11:46 误码
谢了,基本看懂了,能给个计算b'表值的程序吗?[email protected]
支持(0) 反对(0)
  

#2楼 [楼主] 2007-09-19 11:48 Cheney Shue  
@误码
可以
支持(0) 反对(0)
  

#3楼 2008-03-12 16:44 wuxixi
谢谢您这么详细准确的讲解,我毕业设计与CRC32有关,找到这样一份资料很有帮助。请问您有时间讲解一下计算b'表值的程序码?如果可以的话,麻烦您发给我,再次谢谢![email protected]
支持(0) 反对(0)
  

#4楼 2008-03-14 20:10 munababy
多谢BZ,写的很容易懂.辛苦了.感谢你的帮助.
支持(0) 反对(0)
  

#5楼 2008-03-25 15:05 gg
谢谢BZ 看懂了大部分
支持(0) 反对(0)
  

#6楼 2008-11-20 21:08 damo
基本上看懂了,讲得非学好。
支持(0) 反对(0)
  

#7楼 2008-12-01 09:24 gg_shily
Hi, 为什么逆向的时候要先移位在和b做异或操做呢?
支持(0) 反对(0)
  

#8楼 2008-12-04 13:12 王洪波
前面的看懂了,但后面的有些模糊,不过还是要谢谢,这比一些书上写的要详细的多了
支持(0) 反对(0)
  

#9楼 2008-12-21 13:35 grainsea
很明白,谢谢!!o(∩_∩)o...呵呵o(∩_∩)o...
支持(0) 反对(0)
  

#10楼 2008-12-21 16:27 grainsea
感谢,感谢......
支持(0) 反对(0)
  

#11楼 2009-02-20 09:07 未注册用户
谢谢,楼主辛苦了!
支持(0) 反对(0)
  

#12楼 2009-03-03 09:41 dxk
谢谢博主,写得很明白
支持(0) 反对(0)
  

#13楼 2009-05-12 16:21 sophia
Thanks!
支持(0) 反对(0)
  

#14楼 2009-05-21 11:45 diy
写的不错
支持(0) 反对(0)
  

#15楼 2009-05-23 14:23 lujun
谢谢你详细地讲解,看到好几篇相关的文章,看到这一篇觉得最好懂
极力推荐!!
支持(0) 反对(0)
  

#16楼 2009-09-22 22:16 givesser
看了你的讲解,茅塞顿开,谢谢。
  

#17楼 2010-08-25 20:41 sunmar
逆向的能否写清楚些啊?最好举个完整的例子,感觉跟正向的差太多了。
  

#18楼 2010-12-17 16:32 DreamSea  
好文章。转载
支持(0) 反对(0)
  

#19楼 2011-03-30 13:57 白开水易拉罐  
完全没看懂!有时间回来再看。
支持(0) 反对(0)
  

#20楼 2011-10-09 14:19 wangzx  
楼主
//3. 每次迭代,受到影响的是gk的前m位,所以构建一个m位的寄存器S,此寄存器储存gk的前m位。每次迭代计算前先将S的首位抛弃,将寄存器左移一位,同时将g的后一位加入寄存器。若使用此种方法,计算步骤如下
//这段程序怎么实现呢 用C语言,我想了很久都没有想到,特地请教下
支持(0) 反对(0)
  

#21楼 2011-10-13 14:04 it-mac  
今天终于基本看明白了!这么详细的介绍,楼主辛苦了!
支持(0) 反对(0)
  

#22楼 2013-03-11 10:30 Nestler  
现在知道为什么程序里要先左移一位再异或了
原来代码里CRC最高位被省略了。。
支持(0) 反对(0)
  

你可能感兴趣的:(c++)