CRC32算法详细推导(1)

From: http://blog.csdn.net/sparkliang/article/details/5671510

CRC算法详解(1)

作为blog再次发出来,详细描述一下CRC32算法的推导过程。

CRC 算法的数学基础

CRC 算法的数学基础就不再多啰嗦了,到处都是,简单提一下。它是以 GF(2) 多项式算术为数学基础的,GF(2) 多项式中只有一个变量 x ,其系数也只有 0 和 1 ,比如:

    1 *x^6 + 0*x^5 + 1*x^4 + 0*x^3 + 0*x^2 +1*x^1 + 1*x^0

       = x^6 + x^4 + x + 1

加减运算不考虑进位和退位。说白了就是下面的运算规则:

    0 + 0 = 0    0 - 0 = 0

    0 + 1 = 1    0 - 1 = 1

    1 + 0 = 1    1 - 0 = 1

1 + 1 = 0    1 - 1 = 0
看看这个规则,其实就是一个异或运算。

每个生成多项式的系数只能是 0 或 1 ,因此我们可以把它转化为二进制形式表示, 比如 g(x)=x^4 + x + 1 ,那么g(x) 对应的二进制形式就是 10011  于是我们就把 GF(2) 多项式的除法转换成了二进制形式,和普通除法没有区别,只是加减运算没有进位和退位。

比如基于上述规则计算 11010/1001 ,那么商是 11 ,余数就是 101 ,简单吧。

     

CRC 校验的基本过程

采用 CRC 校验时,发送方和接收方用同一个生成多项式 g(x) , g(x) 是一个 GF(2) 多项式,并且 g(x) 的首位和最后一位的系数必须为 1 。

CRC 的处理方法是:发送方用发送数据的二进制多项式 t(x) 除以 g(x) ,得到余数 y(x) 作为 CRC 校验码。校验时,以计算的校正结果是否为 0 为据,判断数据帧是否出错。设生成多项式是 r 阶的(最高位是 x^r )具体步骤如下面的描述。

发送方:

1 )在发送的 m 位数据的二进制多项式 t(x) 后添加 r 个 0 ,扩张到 m+ r 位,以容纳 r 位的校验码,追加 0 后的二进制多项式为  T(x) ;

2 )用 T(x) 除以生成多项式 g(x) ,得到 r 位的余数 y(x) ,它就是 CRC 校验码;

3 )把 y(x) 追加到 t(x) 后面,此时的数据 s(x) 就是包含了 CRC 校验码的待发送字符串;由于 s(x) = t(x) y(x) ,因此 s(x) 肯定能被 g(x) 除尽。

接收方:

1 )接收数据 n(x) ,这个 n(x) 就是包含了 CRC 校验码的 m+r 位数据;

2 )计算 n(x) 除以 g(x) ,如果余数为 0 则表示传输过程没有错误,否则表示有错误。从 n(x) 去掉尾部的 r 位数据,得到的就是原始数据。

生成多项式可不是随意选择的,数学上的东西就免了,以下是一些标准的 CRC 算法的生成多项式:

标准

生成多项式

16 进制表示

CRC12

x^12 + x^11 + x^3 + x^2 + x + 1

0x80F

CRC16

x^16 + x^15 + x^2 + 1

0x8005

CRC16-CCITT

x^16 + x^12 + x^5 + 1

0x1021

CRC32

x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1

0x04C11DB7

原始的 CRC 校验算法

根据多项式除法,我们就可以得到原始的 CRC 校验算法。假设生成多项式 g(x)  r 阶的,原始数据存放在 data中,长度为 len  bit  reg  r+1 位的变量。 以 CRC-4 为例,生成多项式 g(x)=x^4 + x + 1 ,对应了一个 5bits 的二进制数字 10011 ,那么 reg 就是 5 bits 。

reg[1] 表明 reg 的最低位, reg[r+1]  reg 的最高位。

通过反复的移位和进行除法,那么最终该寄存器中的值去掉最高一位就是我们所要求的余数。所以可以将上述步骤用下面的流程描述:

[cpp] view plaincopy
  1. reg = 0;  
  2. data = data追加r个;  
  3. pos = 1;  
  4. while(pos <= len)  
  5. {  
  6.     if(reg[r+1] == 1) // 表明reg可以除以g(x)  
  7.     {  
  8.         // 只关心余数,根据上面的算法规则可知就是XOR运算  
  9.         reg = reg XOR g(x);  
  10.     }  
  11.     // 移出最高位,移入新数据  
  12.     reg = (reg<<1) | (data[pos]);  
  13.     pos++;  
  14. }  
  15. return reg; // reg中的后r位存储的就是余数  

改进一小步——从 r+1 到 r

由于最后只需要 r 位的余数,所以我们可以尝试构造一个 r 位的 reg ,初值为 0 ,数据 data 依次移入 reg[1] ,同时把reg[r] 移出  reg 

根据上面的算法可以知道,只有当移出的数据为 1 时, reg 才和 g(x) 进行 XOR 运算;于是可以使用下面的算法:

 

[cpp] view plaincopy
  1. reg = 0;  
  2. data = data追加r个;  
  3. pos = 1;  
  4. while(pos < len)  
  5. {  
  6.     hi-bit = reg[r];  
  7.     // 移出最高位,移入新数据  
  8.     reg = (reg<<1) | (data[pos]);  
  9.     if(hi-bit == 1) // 表明reg可以除以g(x)  
  10.     {  
  11.         reg = reg XOR g(x);  
  12.     }  
  13.     pos++;  
  14. }  
  15. return reg; // reg中存储的就是余数  

这种算法简单,容易实现,对任意长度生成多项式的 G ( x )都适用,对应的 CRC-32 的实现就是:

[cpp] view plaincopy
  1. // 以4 byte数据为例  
  2. #define POLY 0x04C11DB7L // CRC32生成多项式  
  3. unsigned int CRC32_1(unsigned int data)  
  4. {  
  5.     unsigned char p[8];  
  6.     memset(p, 0, sizeof(p));  
  7.     memcpy(p, &data, 4);  
  8.     unsigned int reg = 0, idx = 0;  
  9.     for(int i = 0; i < 64; i++)  
  10.     {  
  11.         idx = i/8;  
  12.         int hi = (reg>>31)&0x01; // 取得reg的最高位  
  13.         // 把reg左移1bit,并移入新数据到reg0  
  14.         reg = (reg<<1)| (p[idx]>>7);  
  15.         if(hi) reg = reg^POLY; // hi=1就用reg除以g(x)  
  16.         p[idx]<<=1;  
  17.     }  
  18.     return reg;  
  19. }  

从 bit 扩张到 byte 的桥梁

但是如果发送的数据块很长的话,这种方法就不太适合了。它一次只能处理一个 bit 的数据,效率太低。考虑能不能每次处理一个 byte 的数据呢?事实上这也是当前的 CRC-32 实现采用的方法。

这一步骤是通往基于校验表方法的桥梁,让我们一步一步来分析上面逐 bit 的运算方式,我们把 reg 和 g(x) 都采用 bit 的方式表示如下:    

 

考虑把上面逐 bit 的算法执行 8 次,如果某次移出的不是 1 ,那么 reg 不会和 g(x) 执行 XOR 运算,事实上这相当于将 reg 和 0 执行了 XOR 运算。执行过程如下所示,根据 hi-bit 的值,这里的 G 可能是 g(x) 也可能是 0 。

 

从上面的执行过程清楚的看到,执行 8 次后, old-reg 的高 8bit 被完全移出, new-reg 就是 old-reg 的低24bit 和数据 data 新移入的 8bit 和 G 一次次执行 XOR 运算所得到的。

       XOR 运算满足结合律,那就是: A XOR B XOR C = A XOR (B XOR C) ,于是我们可以考虑把上面的运算分成两步进行:

1 )先执行 R 高 8bit 与 G 之间的 XOR 运算,将计算结果存入 X 中,如下面的过程所示。

 

2 )将 R 左移 8bit ,并移入 8bit 的数据,得到的值就是  ,然后再与 X 做 XOR运算。

根据 XOR 运算的结合率,最后的结果就等于上面逐 bit 的算法执行 8 次后的结果,根据这个分解,我们可以修改逐bit 的方式,写出下面的算法。

 

[cpp] view plaincopy
  1. // 以4 byte数据为例  
  2. #define POLY 0x04C11DB7L // CRC32生成多项式  
  3. unsigned int CRC32_2(unsigned int data)  
  4. {  
  5.     unsigned char p[8];  
  6.     memset(p, 0, sizeof(p));  
  7.     memcpy(p, &data, 4);  
  8.     unsigned int reg = 0, sum_poly = 0;  
  9.     for(int i = 0; i < 8; i++)  
  10.     {  
  11.         // 计算步骤1  
  12.         sum_poly = reg&0xFF000000;  
  13.         for(int j = 0; j < 8; j++)  
  14.         {  
  15.             int hi = sum_poly&0x80000000; // 测试reg最高位  
  16.             sum_poly <<= 1;  
  17.             if(hi) sum_poly = sum_poly^POLY;  
  18.         }  
  19.         // 计算步骤2  
  20.         reg = (reg<<8)|p[i];  
  21.         reg = reg ^ sum_poly;  
  22.     }  
  23.     return reg;  
  24. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/404157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端javascript面试题目录汇总

【JS】 [js] 请使用js实现一个秒表计时器的程序 [js] 模拟 localStorage 时如何实现过期时间功能 [js] 请使用js实现商品的自由组合&#xff0c;并说说你的思路 [js] js中的undefined和 ReferenceError: xxx is not defined 有什么区别&#xff1f; [js]JavaScript Number…

React开发(272):try...catch..捕获

//通过接口获取listhandleSearchList async (url) > {try {const res await url();if (res.data && res.data.length > 0) {this.setState({thirdList: res.data,showThird: true,tabName: ,});}} catch (error) {}};

CRC32算法详细推导(2)

From: http://blog.csdn.net/sparkliang/article/details/5671977 CRC算法详解&#xff08;2&#xff09; 初见 Table-Driven 变换到上面的方法后&#xff0c;我们离 table-driven 的方法只有一步之遥了&#xff0c;我们知道一个字节能表示的正整数范围是 0~255&#xff0c;步…

iOS UIWebView加载网页、文件、HTML

UIWebView是用来加载加载网页数据的一个框架.UIWebView可以用来加载pdf,word,doc,等等文件,生成webview 有两种方法&#xff0c;1、通过storyboard 拖拽 2、通过alloc init 来初始化创建webview&#xff0c;下列文本中 _webView.dataDetectorTypes UIDataDetectorTypeAll; 是识…

nginx的upstream模块安装

下载连接&#xff1a;wget http://code.google.com/p/nginx-upstream-jvm-route/downloads/detail?namenginx-upstream-jvm-route-0.2.tar.gz&can1&q/nginx-upstream-jvm-route-0.2.tar.gz nginx_upstream_jvm_route 是一个 Nginx 的扩展模块&#xff0c;用来实现基于…

前端面试题Vue-cli目录汇总

【Vue-cli】 [vue-cli]vue-cli3你有使用过吗&#xff1f;它和2.x版本有什么区别&#xff1f; [vue-cli]vue-cli默认是单页面的&#xff0c;那要弄成多页面该怎么办呢 [vue-cli]不用vue-cli&#xff0c;你自己有搭建过vue的开发环境吗&#xff1f;流程是什么&#xff1f; [v…

CRC32算法详细推导(3)

From:http://blog.csdn.net/sparkliang/article/details/5671543 CRC32算法详细推导&#xff08;3&#xff09; 郁闷的位逆转 看起来我们已经得到 CRC-32 算法的最终形式了&#xff0c;可是、可是在实际的应用中&#xff0c;数据传输时是低位先行的&#xff1b;对于一个字节 …

WebService的学习

这篇文章不错&#xff0c;直接转了 http://blog.csdn.net/terryzero/article/details/5976638#comments 转载于:https://www.cnblogs.com/zhilu-doc/p/5291927.html

linux 用户行为审计

根据公司需求&#xff0c;整理了一个linux用户审计的脚本&#xff0c;现和大家分享&#xff01; 具体步骤如下&#xff1a; 一&#xff1a;配置调试 1.创建用户审计文件存放目录和审计日志文件 &#xff1b; mkdir -p /var/log/usermonitor/ 2.创建用户审计日志文件&#xff1…

前端面试题vue-element汇总

【Vue-element】 [vue-element] ElementUI是怎么做表单验证的&#xff1f;在循环里对每个input验证怎么做呢&#xff1f; [vue-element] 你有二次封装过ElementUI组件吗&#xff1f; [vue-element] ElementUI怎么修改组件的默认样式&#xff1f; [vue-element]ElementUI的穿…

每天一点Swift(五)控制器的生命周期和SizeClass

字数358 阅读19 评论0 喜欢0 初始化init-->awakeFromNib--> prepare a segue --> SB去设置outlets --> viewDidLoad 1. viewDidLoad 在viewDidLoad中&#xff0c;outlets已经被设置&#xff1b;但是几何位置&#xff08;bounds&#xff09;并没有被设置 viewDidLoa…

h264 I帧的判断

From:http://blog.csdn.net/dxpqxb/article/details/13289205 H264数据的NALU 头的格式如图2 所示&#xff1a; F&#xff1a;forbidden_zero_bit.1 位&#xff0c;如果有语法冲突&#xff0c;则为 1。当网络识别此单元存在比特错误时&#xff0c;可将其设为 1&#xff0c;以便…

前端面试题node.js汇总

【NodeJs】 [NodeJs] 你有使用过npx吗&#xff1f;它主要解决什么问题&#xff1f; [NodeJs] 如何使用nodejs对base64进行编解码&#xff1f; [NodeJs] npm提供了哪些钩子&#xff1f;各有什么作用&#xff1f; [NodeJs] 如果发现node_modules中有个模块代码有bug&#xff…

win10 下安装、配置、启动mysql

1、下载http://dev.mysql.com/downloads/mysql/ 2、Community > MySQL Community Server 3、Other Downloads: > Windows (x86, 32-bit), ZIP Archive 5、解压mysql-5.7.11-winx64.zip&#xff0c;解压在 D:\soft\mysql-5.7.11-winx64\mysql-5.7.11-winx64 6、在D:\soft\…

成功驱动HD4600-Clover引导

本人机器配置如下&#xff1a; 操作系统 Windows 7 旗舰版 64位 SP1 ( DirectX 11 ) 处理器 英特尔 Core i7-4770K 3.50GHz 四核 核显&#xff1a; Intel HD4600 主板 华硕 Z87-PRO (英特尔 Haswell) 内存 8 GB ( 金士顿 DDR3 1778MH…

前端软技能面试汇总

【软技能】 [软技能] 在前后端分离项目里&#xff0c;请说说前端传递的token的流程&#xff1f; [软技能] 现如今面对如层出不穷的类库&#xff0c;说说你的感受 [软技能] 你认为计算专业和非计算机专业的差别在哪&#xff1f;为什么&#xff1f; [软技能] png-8和png-24有…

ACM训练计划(上)

一.基本算法: (1)枚举.(poj1753,poj2965) (2)贪心.(poj1328,poj2109,poj2586) (3)递归和分治法. (4)递推. (5)构造法.(poj3295) (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法: (1)图的深度优先遍历和广度优先遍历. (2)最短路…

单硬盘上mac + win7双系统,GUID-GPT分区

首先&#xff0c;当然要介绍下我的环境了。 一、环境介绍 1. 主板是支持UEFI启动的&#xff0c;但是我感觉自己没用到。 2. 我有两个硬盘: hd0: 准备安装mac和win7_x64 hd1: GUID格式&#xff0c;GPT分区&#xff0c;已装有mac10.9.3环境&#xff0c;还有个FAT32的分区&a…

React开发(273):异步调用的方式

1、回调函数方式 doFirstThing((err, data) > {if (err) {console.log(err);return;}doSecondThing(data, function(err, data){if (err) {console.log(err);return;}doThirdThing(data, function(err, data){if (err) {console.log(err);return;}})}) })2、Promise 方式 …

hdu 1166 敌兵布阵 (线段树)

http://acm.hdu.edu.cn/showproblem.php?pid1166最基础的线段树&#xff0c;单点更新。完全跟着HH的代码风格写的。code:#include<cstdio>#define lson l, m, rt<<1#define rson m1, r, rt<<1|1const int maxn 50005 ;int sum[maxn<<2] ;void PushUp…