FEC-Reed-Solomon算法浅析(一)

#### 前言

本文是介绍FEC-Reed—Solomon算法的第一篇,主要介绍伽罗华域的相关知识,因为这个伽罗华域算是这个算法能够广泛被应用在网络通信的大功臣来,我们先来看看伽罗华域是什么。先介绍下创造这个域的人,伽罗华(也译作伽瓦罗),法国数学家,群论的创立者。用群论彻底解决了根式求解代数方程的问题,而且由此发展了一整套关于群和域的理论。这个人比较悲惨的是他死于与其他人的决斗当中,不得不说有点可惜。好了,让我们进入正题。

#### 相关数据概念

##### 域

一组元素的集合,以及在集合上的四则运算,构成一个域。其中加法和乘法必须满足交换、结合和分配的规律。加法和乘法具有封闭性,即加法和乘法结果仍然是域中的元素。域中必须有加法单位元和乘法单位元,且每一个元素都有对应的加法逆元和乘法逆元。但不要求域中的 0有乘法逆元。

##### 有限域

仅含有限多个元素的域。因为它由伽罗华所发现,因而又称为伽罗华域。所以当我们说伽罗华域的时候,就是指有限域。GF($2^w$)表示包含有$2^w$个元素的有限域。

##### 单位元

Identity Element,通常使用e来表示单位元。单位元和其他元素结合时,并不会改变那些元素。 对于二元运算,若ae=a,e称为右单位元;若ea=a,e称为左单位元,若ae=e\*a=a,则e称为单位元。(有点类似于矩阵里面的单位矩阵概念)

##### 逆元

对于二元运算,若ab=e,则a称为b的左逆元素,b称为a的右逆元素。若ab=ba=e,则称a为b的逆元,b为a的逆元。

##### 素多项式

域中不可约多项式是不能够进行因子分解的多项式,素多项式(primitive polynomial)是一种特殊的不可约多项式。当一个域上的素多项式确定了,这个域上的运算也就确定了。素多项式一般通过查表可得,同一个域往往有多个素多项式。通过将域中的元素化为多项式形式,可以将域上的乘法运算转化为普通的多项式乘法再模素多项式。

#### 多项式运算

##### GF($2^w$)下多项式运算

这里不再介绍基本的多项式乘法,这里只介绍一下GF($2^w$)下的多项式运算,对于GF($2^w$)上的多项式计算,多项式系数只能取0或1。(如果是GF($2^w$),那么系数可以取 0、1、2,GF($2^w$)的多项式加法中,合并阶数相同的同类项时,由于0+0=0,1+1=0,0+1=1+0=1,因此系数不是进行加法操作,而是进行异或操作。

GF($2^w$)的多项式减法等于加法,例如$x^4$ – $x^4$就等于$x^4$ + $x^4$进而等于0,因为1+1=1^1=0。

#### 伽罗华域

##### 有限域GF(p)

有限域GF(p),其中p为素数。GF(p)里面的加法和乘法与一般的加法和乘法差不多,区别是结果需要mod p,以保证结果都是域中的元素。GF(p)的加法和乘法单位元分别是 0和1。 GF(p)加法是(a+b) mod p,乘法是(a*b)mod p。

对于域中的乘法,当p为素数时,才能保证集合中的所有的元素都有乘法逆元(0除外)。即对于域中的任一个元素a,总能在域中找到另外一个元素b,使得a*b mod p 等于1。

说明:假如p等于10,其乘法单位元为1。对于元素2,找不到一个数a,使得2*a mod 10 等于1,即2没有乘法逆元。这时,在域上就不能进行除2运算。

##### 有限域GF($2^w$)

GF(p)中p必须是一个素数,才能保证集合中的所有元素都有加法和乘法逆元(0除外)。但实际应用中,很多场合需要 0到255这256个数字能组成一个域。但256不是素数,小于256的最大素数为251,如果直接把大于等于251的数截断为250,则会丢失一部分数据。

因此引入了GF($p^w$),其中p为素数,通常取p=2。计算机领域中经常使用的是GF($2^8$),8刚好是一个字节的比特数。为了保证有限域性质,GF($2^w$)上的加法运算和乘法运算,不再使用一般的加法和乘法,而是使用多项式运算。

这里的核心就是GF($2^8$),因为这个就是我们所需要的,$2^8$大小正好是一个字节,说明我们终于能对一个字节下手了(笑),现在下一个问题就是我们应该怎么知道在GF($2^8$)上应该如何运算呢?下面我们引入之前说过的素多项式

#### GF($2^8$)下的素多项式

伽罗华域的元素可以通过该域上的素多项式生成。通过本原多项式得到的域,其加法单位元都是 0,乘法单位元是1。

以GF($2^3$)为例,指数小于3的多项式共8个:0,1,x,x+1,$x^2$,$x^2$+1,$x^2$ + x $x^2$+x+1。其系数刚好就是000,001, 010, 011, 100, 101, 110, 111,是0到7这8个数的二进制形式。

GF($2^3$)上有不只一个素多项式,但是我们随便选一个素多项式$x^3$+x+1,这8个多项式进行四则运算后mod($x^3$+x+1)的结果都是8个之中的某一个。因此这8个多项式构成一个有限域。

对于GF($2^3$),取素多项式为$x^3$+x+1,那么多项式$x^2$+x的乘法逆元就是x+1。系数对应的二进制分别为110和011。此时,我们就认为对应的十进制数6和3互为逆元。

部分 GF($2^w$)域经常使用的本原多项式如下:
![image.png](https://upload-images.jianshu.io/upload_images/5550522-93d6ae8d2e918e5b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

##### 通过素多项式来生成元素

设P(x)是GF($2^w$)上的某一个本原多项式,GF($2^w$)的元素产生步骤是:

1. 给定一个初始集合,包含0,1,即 {0,1}
2. 将这个集合中的最后一个元素,即x,乘以x,如果结果的度大于等于w,则将结果mod P(x)后加入集合
3. 直到集合有$2^w$个元素,此时最后一个元素乘以x再mod P(x)的值等于1

这里我仍然以GF($2^3$)为例子,素多项式为$x^3$+x+1,GF($2^3$)共有8个元素,除了0、1之外,其他元素都由按照上面的步骤来生成:

| 生成元素 | 多项式表示 | 二进制表示 | 十进制表示 |
| :-----: | :------: | :------: | :------: |
| 0       |     0    |    0     |     0     |
|  $x^0$  |     1    |   001    |     1     |
|  $x^1$  |   $x^1$  |   010    |     2     |
|  $x^2$  |   $x^2$  |   100    |     4     |
|  $x^3$  |    x+1   |   011    |     3     |
|  $x^4$  |$x^2$ + x |   110    |     6     |
|  $x^5$  |$x^2$+x+1 |   111    |     7     |
|  $x^6$  |$x^2$ + 1 |   101    |     5     |
|  $x^7$  |     1    |    1     |     1     |

这里推导过程我就不给出了,其实mod P(x)本质就是将加上P(x)即$x^3$+x+1,由于加法操作是异或操作,所以$x^3$项就被消去了,保证了结果多项式的最高次数不超过3,转换成2进制表示也就不超过8,保证了结果一定是落在[0,7]这个区间内,实际上0是不可能出现的,因为$x^3$+x+1是素多项式。

#### 伽罗华域GF($2^8$)上的线性运算

##### 加法运算

这个比较简单,就是异或运算,同时需要注意的是减法就是加法,都是异或运算

##### 乘法和除法运算

这个稍微复杂一点,伽罗华域上的多项式乘法,其结果需要mod P(x),本质就是加上素多项式$x^8=x^4+x^3+x^2+1$,除法其实就是乘法的逆运算,除以一个数就等于乘以这个数的逆元。
GF($2^8$)符号的表示形式如下:
![image.png](https://upload-images.jianshu.io/upload_images/5550522-3e16133a9f163d02.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这个在计算机计算的时候为了避免大量的计算,一般会采用查表的方式来进行计算,现在的问题就是我们如何获得这个表呢?这里就得先说下如何计算了:
对于一般形式的多项式$f(x)=a7\*x^7 + a6\*x^6 + a5\*x^5 + a4\*x^4 + a3\*x^3 + a2\*x^2 + a1x + a0$,乘以x得到 $xf(x) = (a7\*x^8 + a6\*x^7 + a5\*x^6 + a4\*x^5 + a3\*x^4 + a2\*x^3 + a1\*x^1 + a0x)$ mod P(x)
这时有两种情况:

1. a7 == 0,此时结果是一个小于指数小于8的多项式,不需要取模计算。

2. a7 == 1,则将$x^8$替换为$x^4 + x^3 + x^2 +1$,而不用进行除法取模计算,结果为:$xf(x) = (x^4 + x^3 + x^2 +1) + a6x^7 + a5x^6 + a4x^5 + a3x^4 + a2x^3 + a1x^1 + a0x$,实际上由于我们计算的GF($2^8$),所以系数的取值只能为0或1。

下面我给出表的生成算法:

```cpp
int MM = 8;
int NN = 255;
int alphaToMM = 45;//α^8=α^5+α^3+α^2+1
int* alphaTo = new int[NN+1];
int* expOf = new int[NN+1];

alphaTo[MM] = alphaToMM;
expOf[alphaToMM] = MM;
alphaTo[NN] = 0;
expOf[0] = NN;

int i, shift;
shift = 1;
///在计算指数从1到7的情况
for(i=0; i<MM; i++){
    alphaTo[i] = shift;//2^i
    expOf[alphaTo[i]] = i;
    shift <<= 1;
}
shift = 128;
///计算指数高于7次的情况
for(i=MM+1; i<NN; i++){
   if(alphaTo[i-1] >= shift){
      ///说明多项式的最高次数已经达到7,对应的是上面说的a7==1的情况
      alphaTo[i] = alphaTo[MM] ^ ((alphaTo[i-1]^shift)<<1);//alphaTo[i-1]*alpha+alpha^8
    }else{
      ///说明多项式的最高次数没有到7,直接移位就好
      alphaTo[i] = alphaTo[i-1]<<1;
    }
   expOf[alphaTo[i]] = i;
}
```

关于除法运算,这里其实也比较简单,对于一个给定的多项式比如D(x),如果想要找到它的逆元,先求它对应的指数,即expOf[D(x)],然后计算用255-expOf[D(x)],令结果是k吧,也就是k=255-expOf[D(x)],其实D(x)的逆元就是alphaTo[k],这个比较简单,这里我就不再多说

#### 总结

说到这里伽罗华域就说的差不多了,之后还有两篇文章介绍范德蒙矩阵和实际的一个使用FEC的例子,有全部的计算过程辅助理解。

#### 参考

[伽罗华域](http://abcdxyzk.github.io/blog/2018/04/16/isal-erase-3/)
[GF($2^8$)的生成算法](http://blog.sina.com.cn/s/blog_4572df4e01019wsj.html)
 

上一篇:idea建立项目关联到git仓库操作步骤


下一篇:FEC-Reed-Solomon算法浅析(一)