第2章 CRC数学基础:模2除法、多项式表示

各位,要真正搞懂CRC,数学基础绕不开。说白了,CRC的底层就两个东西:模2除法和多项式表示。你别怕数学,我当年学的时候也觉得头大,后来发现这东西其实比普通算术还简单——只需要会“按位异或”就行。

2.1 模2除法到底是怎么算的?

先问一个问题:普通除法里,我们做减法要借位。但模2除法呢?不借位,只异或。你想想看,这是不是有点像二进制加法不进位?没错,模2加法和减法其实就是同一个操作——异或(XOR)。

我用一个例子带你走一遍。假设被除数 101010,除数 1101(4位)。我们做模2除法求余数:

       11001   ← 商我们不关心
     _______
1101) 101010
     1101    ← 第一轮:对齐最高位,异或
     ----
      1111   ← 结果
      1101   ← 第二轮:再对齐
      ----
       0100  ← 注意这里高位0要保留!实际是100
       0000  ← 除数1101比0100大,商这一位是0
       ----
        1000
        1101  ← ?不对,已经不够了。其实要补位
        实际上最终余数是 001

等一下,这个写法容易乱。我更习惯用表格步骤来展示,看下表:

步骤当前操作数除数异或结果说明
11010101101011110对齐最高位,异或
211110(去掉前置0)1101001100继续对齐高位
311001101000100除数大于当前数,商0,直接拉下一位
410001101001101最终余数 101?不对,漏了步

我承认看表格也可能懵。其实模2除法就跟我们算CRC一样,寄存器左移,移一位异或一次。我在项目中曾经手算过一个32位的CRC值,算到半夜才发现自己少移了一位……后来我都是用程序验证的。

给你一个口诀:位数对齐,高位异或,结果截短,重复直到不够除。

小技巧:你可以在纸上画一个“除法竖式”,但把减法统统替换成异或。记住:异或的结果位数与被除数对齐,前置的0要保留直到遇到第一个1才截取。

2.2 怎么用多项式来表示这些二进制数?

二进制数和多项式其实是一一对应的。假设我们有二进制数 1101,从最高位到最低位分别是第3、2、1、0位(注意从0开始)。那么它对应的多项式就是:

1·x³ + 1·x² + 0·x¹ + 1·x⁰ = x³ + x² + 1

你看,哪一位是1,那个幂次的系数就是1;是0,系数就是0。很好理解吧?说白了,就是把位权从“2的n次方”换成了“x的n次方”。

为什么要这么干?因为模2多项式的加法和乘法,自动满足异或运算的规律。比如:

(x³ + x² + 1) + (x² + x) = x³ + (x² + x²) + x + 1 = x³ + 0 + x + 1 = x³ + x + 1

注意:x² + x² 系数是1+1,在模2下就是0,所以这两项直接消失。这不是和异或一模一样吗?

下面这张SVG图帮你理清这个对应关系:

二进制与多项式对应关系 二进制数 位权:2^n 多项式表示 位权:x^n 示例:二进制 1101 = 多项式 x³ + x² + 1 1 (x³) + 1 (x²) + 0 (x¹) + 1 (x⁰) 模2加法:系数异或(1+1=0) 加法 = 异或 乘法 = 与 + 异或 除法 = 异或 + 移位 CRC核心:用多项式模2除法计算余数作为校验码
核心要点:CRC的校验码,就是把要保护的数据看作一个大多项式,除以一个固定的生成多项式(Generator Polynomial),取余数。这个余数就是CRC值。因为多项式运算天然就是模2的,所以我们用异或做除法。

2.3 常见的生成多项式长什么样?

工程上常用的生成多项式都标准化了。我列一个表,这些都是我在实际项目中用过的:

名称多项式(二进制)多项式表示位宽
CRC-8100000111x⁸ + x² + x + 18
CRC-16-IBM11000000000000101x¹⁶ + x¹⁵ + x² + 116
CRC-CCITT10001000000100001x¹⁶ + x¹² + x⁵ + 116
CRC-32100000100110000010001110110110111x³² + x²⁶ + x²³ + x²² + x¹⁶ + x¹² + x¹¹ + x¹⁰ + x⁸ + x⁷ + x⁵ + x⁴ + x² + x + 132

注意:多项式的最高次项系数总是1,所以在二进制表示中最高位固定为1,正好对应位宽。比如CRC-8需要9位二进制数来表示(因为最高次x⁸需要系数位)。

我曾经踩过的坑:有几次我直接拿了别人代码里的生成多项式常数(比如0x1021),结果发现左对齐和右对齐搞反了,CRC死活算不对。切记:多项式表示有MSB-first和LSB-first两种约定,必须和算法中的移位方向匹配。后面章节我会专门讲对齐问题。

2.4 多项式表示在CRC计算中的优势

用多项式来描述CRC,最大的好处是数学上严谨。你可以把整个通信链路抽象成一个多项式除法系统。比如:

  • 发送数据 = M(x) · x^n(n是生成多项式的次数,相当于在数据末尾补n个0)
  • CRC校验码 = [M(x) · x^n] mod G(x)
  • 发送帧 = M(x) · x^n + CRC
  • 接收端检查:(M(x) · x^n + CRC) mod G(x) 是否等于0

这些公式看起来很抽象?其实你只要理解一件事:CRC本质上就是求余数。多项式只是给这个余数找了个“代数学名字”,方便我们证明它的检错能力。

我在做车载以太网协议栈时,需要证明CRC-32能够100%检测出≤32位的突发错误。用多项式理论推导一遍,心里就踏实了。否则光靠猜,谁敢往车上用?

一句话总结:模2除法是CRC的“算数引擎”,多项式表示是CRC的“身份证”。两者一结合,CRC的数学本质就清楚了。