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

CRC算法详解(2)

初见 Table-Driven

变换到上面的方法后,我们离 table-driven 的方法只有一步之遥了,我们知道一个字节能表示的正整数范围是 0~255,步骤 1 中的计算就是针对 reg 的高 Byte 位进行的,于是可以被提取出来,预先计算并存储到一个有 256 项的表中,于是下面的算法就出炉了,这个和上面的算法本质上并没有什么区别。

[cpp] view plaincopy
  1. #define POLY 0x04C11DB7L // CRC32生成多项式
  2. static unsigned int crc_table[256];
  3. unsigned int get_sum_poly(unsigned char data)
  4. {
  5. unsigned int sum_poly = data;
  6. sum_poly <<= 24;
  7. for(int j = 0; j < 8; j++)
  8. {
  9. int hi = sum_poly&0x80000000; // 取得reg的最高位
  10. sum_poly <<= 1;
  11. if(hi) sum_poly = sum_poly^POLY;
  12. }
  13. return sum_poly;
  14. }
  15. void create_crc_table()
  16. {
  17. for(int i = 0; i < 256; i++)
  18. {
  19. crc_table[i] = get_sum_poly(i&0xFF);
  20. }
  21. }
  22. // 以byte数据为例
  23. unsigned int CRC32_3(unsigned int data)
  24. {
  25. unsigned char p[8];
  26. memset(p, 0, sizeof(p));
  27. memcpy(p, &data, 4);
  28. unsigned int reg = 0, sum_poly = 0;
  29. for(int i = 0; i < 8; i++)
  30. {
  31. // 计算步骤1
  32. sum_poly = crc_table[(reg>>24)&0xFF];
  33. // 计算步骤2
  34. reg = (reg<<8)|p[i];
  35. reg = reg ^ sum_poly;
  36. }
  37. return reg;
  38. }

更进一步

上面的这个算法已经是一个Table-Driven的CRC-32算法了,但是实际上我们看到的CRC校验代码都是如下的形式:<div><div><div style="color:silver;"><strong>[cpp]</strong> <a target=_blank href="http://blog.csdn.net/sparkliang/article/details/5671977#" title="view plain" style="color:rgb(160, 160, 160);">view plain</a><a target=_blank href="http://blog.csdn.net/sparkliang/article/details/5671977#" title="copy" style="color:rgb(160, 160, 160);">copy</a></div></div><ol start="1" style="color:rgb(92, 92, 92);"><li style="color:inherit;"><span style="color:black;">r=0;  </span></li><li><span style="color:black;"><span style="color:rgb(0, 102, 153);">while</span>(len--)  </span></li><li style="color:inherit;"><span style="color:black;">     r = (r<<8) ^ t[(r >> 24) ^ *p++];  </span></li></ol></div>

下面我们将看看是做了什么转化而做到这一点的。

首先上述 CRC 算法中,我们需要为原始数据追加 r/8Byte 个 0 , CRC-32 就是 4Byte 。或者我们可以再计算原始数据之后,把 0 放在后面单独计算,像这样:

[cpp] view plaincopy
  1. // 先计算原始数据
  2. for(int i = 0; i < len; i++)
  3. {
  4. sum_poly = crc_table[(reg>>24)&0xFF];
  5. reg = (reg<<8)|p[i];
  6. reg = reg ^ sum_poly;
  7. }
  8. // 再计算追加的4Byte 0
  9. for(int i = 0; i < 4; i++)
  10. {
  11. reg = (reg<<8) ^ crc_table[(reg>>24)&0xFF];
  12. }

这看起来已经足够好了,而事实上我们可以继续向下进行以免去为了附加的 0 而进行计算。在上面算法中,最后的 4 次循环是为了将输入数据的最后 r/8 位都移出 reg ,因为 0 对 reg 的值并没有丝毫影响。

对于 CRC-32 ,对于任何输入数据 Dn...D8…D5D4…D1 ,第一个 for 循环将 Dn…D8…D5 都依次移入,执行XOR 运算再移出 reg ;并将 D4…D1 都移入了 reg ,但是并未移出;因此最后的 4 次循环是为了将 D4…D1 都移出 reg 。

Di 与 Ri 执行 XOR 运算后值将会更新,设更新后的值表示为 Di’ ,不论执行了多少次 XOR 运算。

如果 reg 初始值是 0 ,那么第一个 for 循环中开始的 4 次循环干的事情就是,把 Dn…Dn-3 移入到 reg 中(与0 做 XOR 结果不变),执行 4 次后 reg 的值就是 Dn.Dn-1.Dn-2.Dn-3 ;

第 5 次循环的结果就是: reg = crc_table[Dn] ^ Dn-1.Dn-2.Dn-3.Dn-4 ;

第 6 次循环的结果就是: reg = crc_table[Dn-1’] ^ Dn-2’.Dn-3’.Dn-4 ; Dn 移出 reg 。

因此上面的计算可以分为 3 个阶段:

1 )前 4 次循环,将 Dn.Dn-1.Dn-2.Dn-3 装入 reg ;

2 )中间的 n-4 次循环,依次将 Di 移入 reg ,在随后的 4 次循环中,依次计算 Di+4 , Di+3 , Di+2 和 Di+1对 Di 的影响;最后移出 reg ;

3 )最后的 4 次循环,实际上是为了计算 D4 , D3 , D2 和 D1 都能执行第 2 步的过程;

具体考察 Di :

1 ) Di 移入到 reg 中, R1=Di ,接着与 crc_table[R4] 执行 XOR 运算;

2 )循环 4 次后, Di 成为 reg 的最高位 R4 ,并且因为受到了 Dn…Di+1 的影响而更新为 Di’ ;

上面的运算步骤如下面所示,其中 F 是对应得 crc_table[R] 的值。

可以清晰的看到,最后 reg 的高 Byte 是 Di 和 F 之间一次次 XOR 运算的结果。依然根据 XOR 运算的结合律,我们可以分两步走:

1)  先执行 F 之间的 XOR 运算,设结果为 FF ,它就是 reg 的首字节;

2)  然后再直接将 Di 和 FF 进行 XOR 运算,并根据结果查 CRC 表;

3)  计算出 XOR 运算后, Di…Di-3 已经移入 reg ;因此再将查表结果和 (reg<<8) 执行 XOR 运算即可;

这就是方法 2 ,于是我们的 table-driven 的 CRC-32 校验算法就可以写成如下的方式了:

[cpp] view plaincopy
  1. reg = 0;
  2. for(int i = 0; i < len; i++)
  3. {
  4. reg = (reg<<8) ^ crc_table[(reg>>24)&0xFF ^ p[i]];
  5. }

CRC32算法详细推导(2)相关推荐

  1. CRC32算法详细推导(3)

    From:http://blog.csdn.net/sparkliang/article/details/5671543 CRC32算法详细推导(3) 郁闷的位逆转 看起来我们已经得到 CRC-32  ...

  2. 【转】卡尔曼滤波算法详细推导(相当值得一看)

    转载自   卡尔曼滤波算法详细推导     这一篇对预备知识的介绍还是很好的,过程与原理讲解也很到位,应该是目前看到中文里最好的讲解了. 一.预备知识 1.协方差矩阵     是一个维列向量,是的期望 ...

  3. Kalman滤波算法详细推导及简单匀速直线运动程序仿真(matlab)

    Kalman滤波算法详细推导及简单匀速直线运动程序仿真(matlab) 起初只是知道Kalman滤波的核心公式和会用,没有仔细研究,最近老师让讲Kalman算法,所以系统的学习了该算法,并结合匀速直线 ...

  4. 扩展卡尔曼滤波(EKF)算法详细推导及仿真(Matlab)

    前言 扩展卡尔曼滤波算法是解决非线性状态估计问题最为直接的一种处理方法,尽管EKF不是最精确的"最优"滤波器,但在过去的几十年成功地应用到许多非线性系统中.所以在学习非线性滤波问题 ...

  5. SMO算法详细推导(Sequential Minimal Optimization)

    本文针对一般性的"软判断的核函数的对偶问题的SVM",形如下式: 上式问题所在:当采样点 xix_ixi​ 选取50000个点时,则基于核函数变量Θ(xi,xj)\bm{\Thet ...

  6. 【深度学习】感知器、线性神经网络案例应用、BP神经网络算法详细推导

    感知器.线性神经网络.BP神经网络及手写数字识别 1. 单层感知器 1.1 感知器的介绍 1.2 感知器的学习规则 1.3 感知器单输入输出示例 1.4 学习率 η\etaη 1.5 模型训练收敛条件 ...

  7. lasso,lars算法详细推导过程-数学

    首发于程序员的伪文艺 关注专栏写文章 从Lasso开始说起 李新春 既可提刀立码,行遍天下:又可调参炼丹,卧于隆中. ​关注他 317 人赞同了该文章 Lasso是Least Absolute Shr ...

  8. em算法 实例 正态分布_【机器学习】EM算法详细推导和讲解

    今天不太想学习,炒个冷饭,讲讲机器学习十大算法里有名的EM算法,文章里面有些个人理解,如有错漏,还请读者不吝赐教. 众所周知,极大似然估计是一种应用很广泛的参数估计方法.例如我手头有一些东北人的身高的 ...

  9. 【2019.11.27】EM算法详细推导

    EM算法 无隐变量下,极大似然函数为: L(θ)=∏iP(xi;θ)L(\theta) = \prod_iP\left(x^{i};\theta\right) L(θ)=i∏​P(xi;θ) 含隐变量 ...

最新文章

  1. Deep Learning for 3D Point Clouds: A Survey 论文阅读
  2. 赠票 | 第三届语言与智能高峰论坛200个免费参会名额!
  3. Java 8 实战 P4 Beyond Java 8
  4. 项目 cmdb(一)
  5. [mysql] mysql-myibatis-整理
  6. 刷bios工具_微星主板怎么更新bios版本?微星主板更新BIOS版本图文教程
  7. iPhoneXI/XI MAX机模曝光:浴霸式摄像头着实抢眼
  8. echarts box
  9. 快捷软件启动工具 Rolan2(转载)
  10. c语言临时变量交换数值,不用临时变量交换两个数的值(C实现)
  11. docker 查看镜像版本_Docker 安装及入门介绍 - 荏苒经十载
  12. IP地址格式 点分十进制
  13. OpenCV-python 自制图片画框脚本
  14. 博客文章分类导引(持续更新)
  15. 中国农垦周先标谋定品牌-万祥军:对话农民丰收节交易会
  16. 别让自己“墙”了自己
  17. 0基础学RS(九)思科AAA认证的本地AAA认证
  18. jquery tmpl()切换页面加载不出问题的解决
  19. 安卓5.0新加辅助功能(高对比性文字/色彩校正/颜色反转)学习
  20. 非对称可搜索加密PEKS复现

热门文章

  1. Wamp5 配置PHP 图文详解(转)
  2. 计算机视觉对扫描文件分类 OCR
  3. 5193. 删除字符使字符串变好
  4. leetcode 191. 位1的个数(位运算)
  5. leetcode306. 累加数(回溯)
  6. 以下是ECMAScript 2016、2017和2018中所有新增功能的示例
  7. facebook移动端框架_2016年所有顶级移动应用均归Google或Facebook所有
  8. 从Jupyter Notebook切换到脚本的5个理由
  9. pca数学推导_PCA背后的统计和数学概念
  10. 基于ASP.NET的新闻管理系统(三)代码展示