【科普向】谁都能看懂的CRC(循环冗余校验)原理

简介

循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。

在数据传输过程中,无论传输系统的设计再怎么完美,差错总会存在,这种差错可能会导致在链路上传输的一个或者多个帧被破坏(出现比特差错,0变为1,或者1变为0),从而接受方接收到错误的数据。为尽量提高接受方收到数据的正确率,在接收方接收数据之前需要对数据进行差错检测,当且仅当检测的结果为正确时接收方才真正收下数据。检测的方式有多种,常见的有奇偶校验、因特网校验和循环冗余校验等。循环冗余校验是一种用于校验通信链路上数字传输准确性的计算方法(通过某种数学运算来建立数据位和校验位的约定关系的)。发送方计算机使用某公式计算出被传送数据所含信息的一个值,并将此值 附在被传送数据后,接收方计算机则对同一数据进行相同的计算,应该得到相同的结果。如果这两个 CRC结果不一致,则说明发送中出现了差错,接收方计算机可要求发送方计算机重新发送该数据。

在计算机网络通信中运用CRC校验时相对于其他校验方法就有一定的优势。CRC可以高比例的纠正信息传输过程中的错误,可以在极短的时间内完成数据校验码的计算,并迅速完成纠错过程,通过数据包自动重发的方式使得计算机的通信速度大幅提高,对通信效率和安全提供了保障。由于 CRC 算法检验的检错能力极强,且检测成本较低,因此在对于编码器和电路的检测中使用较为广泛。从检错的正确率与速度、成本等方面,都比奇偶校验等校验方式具有优势。因而,CRC 成为计算机信息通信领域最为普遍的校验方式

CRC基本原理

模二运算

在对CRC算法进行具体说明前,先来看看什么是模二运算。

移位寄存器的每一级只可能有两种不同的存数(或状态),分别用0和1来表示。这里, 0和1不再具有一般数量的含义,而只具有逻辑含义。对于这样一种只包含0和1两个元素(符号)的集合(叫做二元集)来说,普通的四则运算不再适用,因而必须重新规定一种新的运算规则。所谓模二运算就是这样一种新的运算规则。

模二运算是一种二进制算法。与四则运算相同,模二运算也包括模二加、模二减、模二乘、模二除四种二进制运算。而且,模二运算也使用与四则运算相同的运算符,即“+”表示模二加,“-”表示模二减,“×”或“·”表示模二乘,“÷”或“/”表示模二除。与四则运算不同的是模二运算不考虑进位和借位,即模二加法是不带进位的二进制加法运算,模二减法是不带借位的二进制减法运算。这样,两个二进制位相运算时,这两个位的值就能确定运算结果,不受前一次运算的影响,也不对下一次造成影响。模二运算是编码理论中多项式运算的基础,也是CRC校验技术中的核心部分。

示例:
模二加法模二减法模二乘法模二除法
很容易看出:

  • 模二加法和模二减法的结果是相同的,并且与异或(XOR)运算的结果是一致的。因此,所有用模二减法的地方都可用模二加法来代替,故不用给模二减法定义专用的符号。而且他们均能用异或运算来代替。
  • 奇数个1相加得1,偶数个1相加得0。
  • 模二乘除法与普通乘除法一样演算,唯一的区别是,模二乘法在部分积相加时按模二加,模二除法部分余数相减时按模二减。

这里重点关注模二除法,因为它与CRC算法密切相关,它有三个性质:

  1. 当最后余数的位数小于除数位数时,除法停止。
  2. 当被除数的位数小于除数位数时,则商数为0,被除数就是余数。
  3. 只要被除数或部分余数的位数与除数一样多,且最高位为1,不管其他位是什么数,皆可商1。

二进制系数多项式

对任意的二进制数都构造与其对应的一个二进制系数多项式。例如:10011B,其对应的二进制系数多项式为 P ( x ) = x 4 + x + 1 P(x)=x^{4}+x+1 P(x)=x4+x+1

CRC算法中,对于二进制数都是以二进制系数多项式去描述的。

CRC算法

基于上述铺垫,我们现在可以对CRC算法进行具体说明:CRC 算法的基本思想是将传输的数据当做一个位数很长的数。将这个数模二除以另一个数。得到的余数作为校验数据附加到原数据后面。
CRC基本原理
实际应用时,发送方和接收方按以下方式通信:

  1. 发送方和接收方在通信前,约定好一个预设整数作为除数。
  2. 发送方在发送前根据原始数据和约定好的除数进行模二除法运算生成余数(即CRC码),然后将其附加到原始数据后面一起发送给接收方。
  3. 接收方收到后将其模二除以约定好的除数,当且仅当余数为0时接收方认为没有差错。

示例

假设要传输的原始数据为1101011011B,发送方和接收方在通信前约定好的除数为10011B。由于除数10011B是五位数(5bit),那么假设余数(即CRC码)为四位数(4bit)。因为现在余数未知,所以在进行模二除法运算前先将余数设为0000B,即待发送的数据为11010110110000B。下面开始进行模二除法运算来确定余数(即CRC码):
示例计算CRC
可见余数(即CRC码)为1110B,因此发送方实际发送的是11010110111110B。接收方在接收后需要将其模二除以10011B来进行CRC校验:
示例校验CRC
可见余数为0,因此本次通信没有差错。

CRC算法的数学描述

下面开始运用数学语言来对CRC算法进行描述(就是开始不说人话了hhh):

设原始数据为 D ( x ) D(x) D(x),约定好的除数为 P ( x ) P(x) P(x) P ( x ) P(x) P(x)最高次数为r,模二除法运算的余数为 R ( x ) R(x) R(x),即 R ( x ) = [ 2 r D ( x ) ]   m o d   P ( x ) R(x)=[2^{r}D(x)]\,mod\,P(x) R(x)=[2rD(x)]modP(x),CRC码为 F ( x ) F(x) F(x),实际发送的数据为 T ( x ) T(x) T(x)。显然, T ( x ) = 2 r D ( x ) + F ( x ) T(x)=2^{r}D(x)+F(x) T(x)=2rD(x)+F(x)
所以CRC算法问题变为:求解 F ( x ) F(x) F(x)使 T ( x )   m o d   P ( x ) = 0 T(x)\,mod\,P(x)=0 T(x)modP(x)=0。(这里不考虑正负,所以取模和取余等效)


T ( x )   m o d   P ( x ) = [ 2 r D ( x ) + F ( x ) ]   m o d   P ( x ) = { [ 2 r D ( x ) ]   m o d   P ( x ) + F ( x )   m o d   P ( x ) }   m o d   P ( x ) = { R ( x ) + F ( x )   m o d   P ( x ) }   m o d   P ( x ) T(x)\,mod\,P(x)\\=[2^{r}D(x)+F(x)]\,mod\,P(x)\\=\{[2^{r}D(x)]\,mod\,P(x)+F(x)\,mod\,P(x)\}\,mod\,P(x)\\=\{R(x)+F(x)\,mod\,P(x)\}\,mod\,P(x) T(x)modP(x)=[2rD(x)+F(x)]modP(x)={[2rD(x)]modP(x)+F(x)modP(x)}modP(x)={R(x)+F(x)modP(x)}modP(x)

注意,这里是模二加法。因此,取 F ( x ) = R ( x ) F(x)=R(x) F(x)=R(x)可以使 { R ( x ) + F ( x )   m o d   P ( x ) }   m o d   P ( x ) = [ R ( x ) + R ( x ) ]   m o d   P ( x ) = 0   m o d   P ( x ) = 0 \{R(x)+F(x)\,mod\,P(x)\}\,mod\,P(x)=[R(x)+R(x)]\,mod\,P(x)=0\,mod\,P(x)=0 {R(x)+F(x)modP(x)}modP(x)=[R(x)+R(x)]modP(x)=0modP(x)=0

F ( x ) = R ( x ) = [ 2 r D ( x ) ]   m o d   P ( x ) F(x)=R(x)=[2^{r}D(x)]\,mod\,P(x) F(x)=R(x)=[2rD(x)]modP(x)

常用CRC版本

上面介绍了CRC基本原理以及 F ( x ) F(x) F(x)的求解,但一直没有探讨如何来“约定”一个好的 P ( x ) P(x) P(x)。实际上, P ( x ) P(x) P(x)是由一种称为本原元的特殊多项式计算而来的, P ( x ) P(x) P(x)应该满足:

  • 最高位和最低位都是1
  • 当被传送信息任何一位发生错误时, P ( x ) P(x) P(x)不被 T ( x ) T(x) T(x)整除
  • 不同位发生错误时,余数应该不同
  • 对余数继续做模二除法时,应该使余数循环

基于这些限定条件,在有限域内求解本原元以及对 P ( x ) P(x) P(x)的取值是通信领域的一个研究课题(没有再深究下去了)。

下面列出常用的研究成果:

名称多项式表示法应用举例
CRC-8X8+X2+X+10X07
CRC-12X12+X11+X3+X2+X+10X80Ftelecom systems
CRC-16X16+X15+X2+10X8005Bisync, Modbus, USB, ANSI X3.28, SIA DC-07, many others; also known as CRC-16 and CRC-16-ANSI
CRC-CCITTX16+X12+X5+10X1021ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS
CRC-32X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X+10x04C11DB7ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS
CRC-32CX32+X28+X27+X26+X25+X23+X22+X20+X19+X18+X14+X13+X11+X10+X9+X8+X6+10x1EDC6F41iSCSI, SCTP, G.hn payload, SSE4.2, Btrfs, ext4, Ceph

表中的多项式均省略了最高位(1)。
从这里可以很容易看出奇偶校验实际上是CRC校验的其中之一(CRC-1)

CRC算法的编程实现

CRC算法的编程实现方法较多,例如直接计算、正向查表、逆向查表等。这里以直接计算CRC32为例说明其编程实现:

CRC-32/ISO-HDLC算法模型
width=32 poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926 residue=0xdebb20e3 name=“CRC-32/ISO-HDLC”
(数据来源:http://reveng.sourceforge.net/crc-catalogue/

其中:

  • width是CRC码的位宽;
  • poly是省略最高位的多项式,因为更利于编程实现,即移位之后不需要考虑最高位;
  • init是CRC码初始值,因为原始数据可能以不同位数的0开头,所以需要设置初始值来区分;
  • refin是输入逆向标志位,这里为真,表示输入数据需要先进行逆向(即按位倒序),再进行后续运算;
  • refout是输出逆向标志位,这里为真,表示CRC码需要先进行逆向(即按位倒序),再输出;
  • xorout是输出异或值,是输出CRC码前与其进行异或运算的数;
  • check是以UTF-8字符串"123456789"(作为8位字符数组)当做输入原始数据计算出的CRC码;
  • residue是以无错误码字当做输入原始数据计算出的、不进行输出异或运算的CRC码,其具体含义有待进一步考究;
  • name是算法名称。

下面开始根据此模型编制实现代码(C/C++):

#include<stdio.h>


#define POLY 0x04c11db7 
#define INIT 0xffffffff 
#define XOROUT 0xffffffff 


/*
将输入的数按位倒序
*/
unsigned int reverse(unsigned int input)
{
	unsigned int output = 0;
	for (unsigned int i = 1; i != 0; i <<= 1)//注意i与input类型一致,保证正确的循环次数
	{
		output <<= 1;//将output左移使上一次循环中确定的位变为高位,同时在本次循环中确定LSB
		if (input & 1)//根据当前input的LSB确定当前output的LSB
		{
			output |= 1;
		}
		input >>= 1;//将input右移以便在下一次循环中获取下一个高位
	}
	return output;
}


/*
按照CRC-32/ISO-HDLC算法模型计算CRC码
*/
unsigned int crc32(unsigned char* addr, unsigned int num)
{
	unsigned int crc = INIT;
	while (num-- > 0)//根据输入数据的数量依次计算
	{
		crc ^= reverse(*addr++);//因refin为真,故将输入逆向
		for (int i = 0; i < 8; i++)//对每次输入的八位数进行计算
		{
			if (crc & 0x80000000)//若首位是1则进行左移并与多项式进行异或运算
			{
				crc = (crc << 1) ^ POLY;
			}
			else//否则继续左移
			{
				crc <<= 1;
			}
		}
		crc &= 0xffffffff;//确保每次计算结果均为32位数值
	}
	return reverse(crc ^ XOROUT);//因refout为真,故将输出逆向
}


int main()
{
	unsigned char input[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
	printf("check=0x%08x\n", crc32(input, sizeof(input)));
}

运行结果与模型中的一致:
运行结果
注意,该算法对数据流逐位进行计算,效率很低。实际应用中较常用的算法之一是按字节查表的快速算法,即先把八位二进制数的CRC码提前计算好并放入表中,实际对数据流处理时可以按字节查表来快速处理。其具体实现这里就不展开了。有兴趣可以继续浏览博主的另一篇博文:https://blog.csdn.net/weixin_44256803/article/details/111794445

  • 121
    点赞
  • 325
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
### 回答1: 范畴论是一门数学领域的学科,主要研究的是集合的抽象概念,以及集合之间的关系。它提供了一个表示数学对象和关系的通用框架,这些对象包括向量空间、图、群、代数等。 计算机科学中,范畴论可以应用于编程语言和程序设计的研究,如类型理论,它是一种表示程序语言中的数据类型和类型间关系的理论。类型理论的目的是使程序的错误在编写代码时尽早发现,以避免在程序运行时发生错误。 另外,范畴论在计算机图形学、人工智能和计算机科学教育等领域也有所应用。例如,在计算机图形学中,范畴论可以用于描述图形的抽象概念,以及图形之间的关系。在人工智能领域,范畴论可以用于研究机器学习中的模型和算法。 总的来说,范畴论是一个重要的数学工具,它为计算机科学中的许多领域提供了有用的抽象概念和理论基础。 ### 回答2: 范畴论是一种抽象数学的分支,主要研究对象是范畴与其间的映射关系。范畴论的基本概念是“范畴”,它由对象(或称为背景集合)和态射(或称为箭头)组成,满足一定的公理。范畴论将数学中的各个分支联系在一起,并提供了一种通用的语言和工具,用于研究和交流数学概念。 范畴论对计算机科学有着广泛应用和影响。首先,范畴论为计算机科学提供了一种抽象的数学语言,用于描述和分析计算模型、算法和计算过程。例如,通过引入范畴论的概念,研究者可以将不同种类的计算模型进行比较和统一,为计算理论提供更精确和一般的描述。 其次,范畴论在编程语言的设计和类型系统的构建中发挥着重要作用。通过研究范畴和范畴之间的映射,可以理解和形式化程序的结构和行为,从而提供更安全、可靠和高效的编程方式。范畴论的相关概念,如函子、自然变换和代数数据类型等,被广泛应用于函数式编程语言和类型系统的设计中。 此外,范畴论还为计算机科学中的其他领域如人工智能、并行计算、数据库理论等提供了研究工具和方法。通过范畴论的观点,可以更好地理解和分析这些领域中的问题,推动领域内的理论研究和应用创新。 总之,范畴论作为一种抽象数学的工具,对于计算机科学的发展和应用具有重要的意义。它为计算模型的研究提供了一种统一的语言和框架,为编程语言的设计和类型系统的构建提供了理论基础,同时也为其他计算机科学领域的研究和应用提供了方法和工具。 ### 回答3: 范畴论是数学的一个分支,它研究对象和结构不同的数学领域之间的关系。范畴论的基本概念是“范畴”,它由对象和箭头组成。对象是数学结构的抽象,而箭头表示对象之间的映射关系。范畴论的目的是研究对象和箭头之间的关系,这些关系可以用于比较和研究不同数学结构之间的性质和相似性。 在计算机科学领域,范畴论有着广泛的应用。首先,它可以用于描述和分析计算模型和计算过程。范畴论的概念可以帮助我们理解和解释计算过程中的抽象和映射关系。例如,函数式编程语言中的高阶函数和类型系统,就可以通过范畴论的概念来解释和理解。 其次,范畴论还可以用于研究和设计计算机程序的语义和语法。范畴论提供了一种抽象的框架,使我们可以将程序的行为和结构表示为对象和箭头的组合。这种表示方式可以帮助我们理解程序的含义和行为,并且可以用于验证程序的正确性和性能。 此外,范畴论还可以应用于计算机科学中的其他领域,例如机器学习、数据挖掘和人工智能等。通过引入范畴论的概念和方法,我们可以更好地理解和分析这些领域中的数学模型和算法,从而提高它们的效率和可靠性。 总的来说,范畴论在计算机科学中的应用非常广泛。它提供了一种抽象的方法和理论框架,可以用于描述、分析和设计各种数学结构和计算过程。范畴论的应用可以帮助我们理解和优化计算机程序的行为和性能,提高计算科学的发展水平。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值