常用校验算法
Posted 夏沫の浅雨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常用校验算法相关的知识,希望对你有一定的参考价值。
写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
目录
一、奇偶校验
1、介绍
奇偶校验位(英语:parity bit)或校验比特(英语:check bit)是一个表示给定位数的二进制数中1的个数是奇数还是偶数的二进制数。奇偶校验位是最简单的错误检测码。
2、原理
奇偶校验常见于串口数据收发,如其名,可分为奇校验和偶校验:
-
奇校验:原始码流+校验位,其 “1” 的个数为奇数,则校验位为 “0”;若为偶数,则校验位为 “1”。
-
偶校验:原始码流+校验位,其 “1” 的个数为奇数,则校验位为 “1”;若为偶数,则校验位为 “0”。
奇校验是在每个字节后增加一个附加位,使得 “1” 的总数为奇数;而偶校验是在每个字节后增加一个附加位,使得 “1” 的总数为偶数。
eg:
以偶校验位来说,如果一组给定数据位中1的个数是奇数,补一个bit为1,使得总的1的个数是偶数。例:0000001, 补一个bit为1, 00000011。
以奇校验位来说,如果给定一组数据位中1的个数是奇数,补一个bit为0,使得总的1的个数是奇数。例:0000001, 补一个bit为0, 00000010。
其原理是:假如采用奇校验,发送端发送的一个字符编码(含校验位)中,“1” 的个数一定为奇数个,在接收端对接收字符二进制位中的 “1” 的个数进行统计,若统计出 “1” 的个数为偶数个,则意味着传输过程中有 1位(或奇数位)发生差错。
2、应用场景
奇校验通常用于同步传输;偶校验常用于异步传输或低速传输。
3、总结
虽然这个校验应该算是校验算法中最简单的,可是它却有不足之处:
如果数据传输过程只有奇数个码位变化,那么不管变化在哪我们都可以直接判断数据传输是错误的,但是一旦有偶数位发生了变化,或者出现移位情况,我们就无法检测到错误,该方法的校错率是 50%。
eg:
奇校验 正确码流 11000001
错 1位 11000011
变成了偶数个 1,能检测出错误
错 2位 11001011
变成了奇数个 1,检测不出错误
出现移位 11000010
变成了奇数个 1,检测不出错误
二、校验和
1、介绍
校验和(英语:Checksum)是冗余校验的一种形式。 它是通过错误检测方法,对经过空间(如通信)或时间(如计算机存储)所传送数据的完整性进行检查的一种简单方法。
2、原理
所谓校验和,就是将被校验数据进行 “累加”,并省略 “累加” 溢出的位,最终得到的 1个或多个字节的结果。这个 “累加”,可以是简单的整数加法校验,又或者是反码加法校验等等。
一般常用的有:
A、整数加法校验和(Integer Addition Checksum)
其操作如加法运算一样,把数据值累加,最后省略高位。
在熟知其操作后,我们来看下误码率;假设传输数据以两个 bit为单位,进行传输两个两位数 00b
和 00b
,则该校验和为:00+00=00,那么在传输过程中其出现错码的数据有以下,那么来简单分析下本次校验出错的概率有多少:
00b | 01b | 10b | 11b | |
---|---|---|---|---|
00b | 00b | 01b | 10b | 11b |
01b | 01b | 10b | 11b | 00b |
10b | 10b | 11b | 00b | 01b |
11b | 11b | 00b | 01b | 00b |
如上表所示,在传输两个两位数 00b
和 00b
时,会有其余三种组合相加校验和也是 00,所以有 3/16 的概率会校验出错的,约为 1/4;但当数据的位宽越大,校验出错概率越低。
B、反码加法校验和(One’s Complement Addition Checksum)
反码加法校验,实际就是先进行整数加法运算,然后将进位加回来。
该处理相对于上一个的整数加法校验,由于需要加上进位操作,所以校验出错概率比它低一点。
3、补充
由于有讲到 One’s Complement
,所以在这里稍微说一下:one’s-complement 和 two’s-complement以及 one’s complement sum和 two’s complement sum。
-
one’s-complement 和 two’s-complement
前者表示:反码,高位为符号位;后者表示:补码,高位为符号位。
参考:https://tutorialspoint.dev/computer-science/computer-organization-and-architecture/whats-difference-between-1s-complement-and-2s-complement
-
one’s complement sum和 two’s complement sum
前者表示:反码加法,需要加上进位;
后者表示:补码加法,舍弃进位。
参考:《Short description of the Internet checksum》
三、循环冗余校验(CRC)
1、介绍
循环冗余校验(英语:Cyclic redundancy check,通称“CRC”)是一种根据网络数据包或电脑文件等数据产生简短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误。生成的数字在传输或者存储之前计算出来并且附加到数据后面,然后接收方进行检验确定数据是否发生变化。由于本函数易于用二进制的电脑硬件使用、容易进行数学分析并且尤其善于检测传输通道干扰引起的错误,因此获得广泛应用。
2、CRC多项式
多项式的选择是 CRC算法实现中最重要的部分,所选择的多项式必须有最大的错误检测能力,同时保证总体的碰撞概率最小。多项式最重要的属性是它的长度,也就是最高非零系数的数值,因为它直接影响着计算的校验和的长度。
最常用的多项式长度有
- 9位(CRC-8)
- 17位(CRC-16)
- 33位(CRC-32)
- 65位(CRC-64)
在构建一个新的 CRC多项式或者改进现有的 CRC时,一个通用的数学原则是使用满足所有模运算不可分解多项式约束条件的多项式。
- 这种情况下的不可分解是指多项式除了 1与它自身之外不能被任何其它的多项式整除。
生成多项式的特性可以从算法的定义中推导出来:
- 如果 CRC有多于一个的非零系数,那么 CRC能够检查出输入消息中的所有单数据位错误。
- CRC可以用于检测短于 2k的输入消息中的所有双位错误,其中k是多项式的最长的不可分解部分的长度。
- 如果多项式可以被 x+1整除,那么不存在可以被它整除的有奇数个非零系数的多项式。因此,它可以用来检测输入消息中的奇数个错误,就像奇偶校验函数那样。
3、多项式与二进制数码
假设一个多项式为 G(x)=x^4+x^3+x+1
, 可转换为二进制数码 11011b
。
等式 G(X)=x^4+x^3+x+1
,可以写成 G(X) = 1*(X^4) + 1*(X^3) + 0*(X^2) + 1*(X^1) + 1*(X^0)
总结:有幂次就为 1,没有幂次就为 0,首尾一定要是 1, 所以 G(x)=x^4+x^3+x+1
为 11011b
。
4、CRC校验核心
从上面可以看出,CRC校验中有两个关键点:
- 一是要预先确定一个发送端和接收端都用来作为除数的二进制比特串(或多项式);
- 二是把原始帧与上面选定的除进行二进制除法运算,计算出 FCS。
前者可以随机选择,也可按国际上通行的标准选择,但最高位和最低位必须均为 “1”,如在 IBM的 SDLC(同步数据链路控制)规程中使用的 CRC-16(也就是这个除数一共是17位)生成多项式 G(x)= x^16 + x^15 + x^2 +1
(对应二进制比特串为:11000000000000101b
);而在 ISO HDLC(高级数据链路控制)规程、ITU的 SDLC、X.25、V.34、V.41、V.42等中使用 CCITT-16生成多项式 G(x)= x^16 + x^15 + x^5 +1
(对应二进制比特串为:11000000000100001b
)。
5、校验原理
CRC算法的是以GF(2)(2元素伽罗瓦域)多项式算术为数学基础的,原理看起来比较复杂、好难懂,但实际上它的主要特点和运算规则是很好理解的。
在 CRC算法中,其运算法制使用 “模 2算术”运算。
A、模 2加减法运算
-
模 2加法运算:1+1=0,0+1=1,0+0=0,无进位,也无借位
-
模 2减法运算:1-1=0,0-1=1,1-0=1,0-0=0,无进位,也无借位
显然,加和减是一样的效果(故在GF(2)多项式中一般不出现 “-” 号),相当于二进制中的逻辑异或运算;也就是相互比较后,两者对应位相同则结果为 “0”,不同则结果为 “1”。
eg:
多项式:P1 = x^3 + x^2 + 1,P2 = x^3 + x^1 + 1,P1 + P2 =
x^3 + x^2 + 1
+ x^3 + x^1 + 1
------------------------------
x^2 + x^1
二进制:P1 = 1101,P2 = 1011,P1 + P2 =
1 1 0 1
+ 1 0 1 1
--------------
1 1 0
B、模 2乘法运算
GF(2)多项式乘法和一般多项式乘法基本一样,只是在各项相加的时候按模 2算术进行,同样的,无进位,也无借位。
eg:
多项式:P1 = x^3 + x^2 + 1,P2 = x^3 + x^1 + 1,P1 x P2 =
(x^3 + x^2 + 1) (x^3 + x^1 + 1)
= (x^6 + x^4 + x^3
+ x^5 + x^3 + x^2
+ x^3 + x + 1)
= x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
二进制:P1 = 1101,P2 = 1011,P1 x P2 =
1 1 0 1
x 1 0 1 1
--------------------
1 1 0 1
1 1 0 1
0 0 0 0
+ 1 1 0 1
--------------------
1 1 1 1 1 1 1
C、模 2除法运算
多项式:P1 = x^5 + x^2 + 1,P2 = x^3 + x^2 + x^1,P1 / P2 =
x^2 x^1
----------------------------------
x^3 + x^2 + x^1 ) x^5 + x^2 + 1
x^5 + x^4 + x^3
----------------------------------
x^4 + x^3 + x^2
x^4 + x^3 + x^2
----------------------------------
1
二进制:P1 = 100101,P2 = 1110,P1 x P2 =
1 1
---------------
1 1 1 0 ) 1 0 0 1 0 1
1 1 1 0
---------------
1 1 1 0
1 1 1 0
---------------
1
具体来说,CRC校验原理就是以下几个步骤:
(1)先选择(可以随机选择,也可按标准选择,具体在后面介绍)一个用于在接收端进行校验时,对接收的帧进行除法运算的除数(是二进制比较特串,通常是以多项方式表示,所以 CRC又称多项式编码方法,这个多项式也称之为“生成多项式”)。
(2)看所选定的除数二进制位数(假设为k位),然后在要发送的数据帧(假设为m位)后面加上 k-1位 “0”,然后以这个加了 k-1个 “0“的新帧(一共是 m+k-1位)以 “模 2除法”方式除以上面这个除数,所得到的余数(也是二进制的比特串)就是该帧的 CRC校验码,也称之为 FCS(帧校验序列)。但要注意的是,余数的位数一定要是比除数位数只能少一位,哪怕前面位是 0,甚至是全为 0(附带好整除时)也都不能省略。
(3)再把这个校验码附加在原数据帧(就是 m位的帧,注意不是在后面形成的 m+k-1位的帧)后面,构建一个新帧发送到接收端,最后在接收端再把这个新帧以 “模 2除法” 方式除以前面选择的除数,如果没有余数,则表明该帧在传输过程中没出错,否则出现了差错。
6、计算步骤
假设以最常用的 CRC-16_MODBUS为例:
(1)、预置 1个16位的寄存器值 0xFFFF,称此寄存器为CRC寄存器;
(2)、把第一个 8位二进制数据(既通讯信息帧的第一个字节)与 16位的 CRC寄存器的低 8位相异或,把结果放于 CRC寄存器,高八位数据不变;
(3)、把 CRC寄存器的内容右移一位(朝高位)用 0填补最高位,并检查右移后的移出位;
(4)、如果移出位为 0则重复第 3步(再次右移一位);如果移出位为1,那么将 CRC寄存器与一多项式(A001)进行异或;
(5)、重复步骤 3和 4,直到右移 8次,这样整个 8位数据全部进行了处理;
(6)、重复步骤 2到步骤 5,进行通讯信息帧下一个字节的处理;
(7)、将该通讯信息帧所有字节按上述步骤计算完成后,得到的 16位CRC寄存器的高、低字节进行交换;
(8)、最后得到的 CRC寄存器内容即为:CRC码。
以上计算步骤中的多项式 A001是 8005按位颠倒后的结果。
6、CRC-16实现代码
这里只演示常用的 CRC-16的部分程序:
Algorithm | Poly | Init | RefIn | RefOut | XorOut |
---|---|---|---|---|---|
CRC16_CCITT | 0x1021 | 0x0000 | true | true | 0x0000 |
CRC16_CCITT_FALSE | 0x1021 | 0xFFFF | false | false | 0x0000 |
CRC16_XMODEM | 0x1021 | 0x0000 | false | false | 0x0000 |
CRC16_X25 | 0x1021 | 0xFFFF | true | true | 0xFFFF |
CRC16_MODBUS | 0x8005 | 0xFFFF | true | true | 0x0000 |
CRC16_IBM | 0x8005 | 0x0000 | true | true | 0x0000 |
CRC16_MAXIM | 0x8005 | 0x0000 | true | true | 0xFFFF |
CRC16_USB | 0x8005 | 0xFFFF | true | true | 0xFFFF |
以上是关于常用校验算法的主要内容,如果未能解决你的问题,请参考以下文章