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

2023-11-08

简介

循环冗余校验(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-8 X8+X2+X+1 0X07
CRC-12 X12+X11+X3+X2+X+1 0X80F telecom systems
CRC-16 X16+X15+X2+1 0X8005 Bisync, Modbus, USB, ANSI X3.28, SIA DC-07, many others; also known as CRC-16 and CRC-16-ANSI
CRC-CCITT X16+X12+X5+1 0X1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS
CRC-32 X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X+1 0x04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS
CRC-32C X32+X28+X27+X26+X25+X23+X22+X20+X19+X18+X14+X13+X11+X10+X9+X8+X6+1 0x1EDC6F41 iSCSI, 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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 二叉树深度的计算

    1 最大深度 根节点到最远叶子节点路径上的节点数 def maxdepth root if not root return 0 if not root rchild and not root lchild return 1 else ml
  • 绿色校园建设

    王兰 安科瑞电气股份有限公司 上海嘉定 201801 摘要 伴随当前环保理念的不断发展 绿色节能理念也在逐步深入校园 为响应国家建设节约型校园的号召 本文以校园智能化综合能效管理平台建设为主题 介绍了平台建设方案 比较了某高校平台建设前后学
  • 美图赶上了AIGC浪潮?

    8月28日 美图公司 1357 HK 正式披露了2023中期业绩 报告期内 公司实现总收入12 61亿元 人民币 下同 同比增长29 8 经调整后归属于母公司权益持有人的净利润1 51亿元 同比增长320 4 从财报上看 美图公司上半年的收
  • python+pywinauto+lackey实现pc端exe自动化

    python pywinauto lackey实现PC端exe自动化 欢迎阅读 框架介绍 环境搭建 Tim自动化 完整代码 写在最后 欢迎阅读 最近一年多一直在从事PC端exe的测试 也是趁着闲余时间 调研了下exe的自动化 核心框架为py
  • 剪绳子(剑指offer 14-1题)

    这道题我拿到之后觉得第一个比较麻烦的点就是分成多少段是不确定的 处理起来就比较抽象 于是自然联想到分段数处理 于是我构建了一个函数getMax int n int i 它用来求长为n的绳子分成i段的最大积 然后在调用处循环每一个可能的i 取
  • 国内最强推荐系统,保姆级学习路线!!(含时间分配规划)

    最近秋招快要结束了 然后一直有很多小伙伴经常在后台私信我计算机专业关于学习路线的问题 可能还是因为没有真正工作而感到迷茫 而我也作为科班生一路走来 真的深知如果没有一个明确的方向 真的很容易走弯路 浪费大把的时间 了解我的小伙伴知道 我毕业
  • 使用UIUC数据集进行汽车检测

    第一步骤 下载数据集 https pan baidu com s 1tk10m8fh 7 MT4NJ29my4g 密码 wdzr 第二步骤 编写代码 如下 import cv2 import numpy as np from os path
  • latex±号_latex中数学符号

    latex中数学符号 常见数学中的特殊符号 缺失 latex中符号3610 9 alpha alfa 阿耳法 beta beta 贝塔 gamma gamma 伽马 deta delta 德耳塔 epsilon epsilon 艾普西隆 z
  • console.writeline($“{}{}“);

    console writeline 作用是将 内容当做表达式 例如 class MyClass public int val 20 class Program static void MyMethod MyClass f1 int f2 f
  • python字典和集合属于无序序列吗_python-序列、集合及字典

    组合数据类型 1 集合类型 集合是多种元素的无序组合 元素独一性 集合用大括号 表示 元素用 分隔 用set函数建立 A set python123 p y t h o n 1 2 3 集合操作符 集合有四种基础运算方法 并 交 差 补 S
  • 关于pads生产文件的导出

    1 solder mask solder mask 是阻焊层出的是负片 它的设置一般如图所示 这个是一般常规设置 如果器件焊盘已经专门做了阻焊焊盘 则可以按如图所示设置 如果选择top层焊盘 设备设置可以选择缩放为4 如果选择solder
  • EVE-NG网卡桥接,带您走进更高级的实验

    原帖地址 http www mamicode com info detail 1819599 html 一 给EVE NG添加虚拟的物理网卡 不管什么样的网卡 方法都类似 为什么说是虚拟的物理网卡呢 这个VMnet1网卡本身就是虚拟出来的
  • 一篇文章让你了解大数据挖掘技术

    大数据如果想要产生价值 对它的处理过程无疑是非常重要的 其中大数据分析和大数据挖掘就是最重要的两部分 在前几期的科普中 小编已经为大家介绍了大数据分析的相关情况 本期小编就为大家讲解大数据挖掘技术 让大家轻轻松松弄懂什么是大数据挖掘技术 什
  • 01 Datafountain_云状识别_top1

    01 Datafountain 云状识别 top1 摘要 1 云状识别算法总体思路和架构 2 云状识别算法具体实现过程 2 1 图像增强 2 2 多图像尺寸训练 2 3 选用densenet161预训练模型进行fine tune 2 4 差
  • Kotlin-Retrofit2和Rxjava2的网络封装,展示Github的用户信息

    目录 开始 1 先添加依赖 2 封装请求类 3 RESTful API请求响应的处理 4 线程与生命周期 5 使用 效果如下 开始 1 先添加依赖 Retrofit相关 implementation com squareup okhttp3
  • git did not exit cleanly (exit code 128) 的解决办法

    问题描述 在新建一个空的本地git仓库后 打算将远程仓库中的代码Pull到本地时异常 具体异常内容如下 git exe pull progress v no rebase origin masterPOST git upload pack
  • CRC-16校验原理

    1 循环校验码 CRC码 是数据通信领域中最常用的一种差错校验码 其特征是信息字段和校验字段的长度可以任意选定 2 生成CRC码的基本原理 任意一个由二进制位串组成的代码都可以和一个系数仅为 0 和 1 取值的多项式一一对应 例如 代码10
  • 【LeetCode】349. 两个数组的交集

    题目 给定两个数组 编写一个函数来计算它们的交集 示例 1 输入 nums1 1 2 2 1 nums2 2 2 输出 2 示例 2 输入 nums1 4 9 5 nums2 9 4 9 8 4 输出 9 4 说明 输出结果中的每个元素一定
  • Go语言面试题--基础语法(14)

    文章目录 1 切片 a b c 的长度和容量分别是多少 2 下面代码中 A B 两处应该怎么修改才能顺利编译 3 下面代码输出什么 1 切片 a b c 的长度和容量分别是多少 func main s 3 int 1 2 3 a s 0 b
  • 【科普向】谁都能看懂的CRC(循环冗余校验)原理

    CRC原理 简介 CRC基本原理 模二运算 二进制系数多项式 CRC算法 示例 CRC算法的数学描述 常用CRC版本 CRC算法的编程实现 简介 循环冗余校验 Cyclic Redundancy Check CRC 是一种根据网络数据包或计