算数编码是一种非常有用的无损信源压缩编码方式,以下是它的详解:
转自https://segmentfault.com/a/1190000011561822
编码原理
算数编码的原理我个人感觉其实并不太容易用三言两语直观地表达出来,其背后的数学思想则更是深刻。当然在这里我还是尽可能地将它表述,并着重结合例子来详细讲解它的原理。
简单来说,算数编码做了这样一件事情:
- 假设有一段数据需要编码,统计里面所有的字符和出现的次数。
- 将区间 [0,1) 连续划分成多个子区间,每个子区间代表一个上述字符, 区间的大小正比于这个字符在文中出现的概率 p。概率越大,则区间越大。所有的子区间加起来正好是 [0,1)。
- 编码从一个初始区间 [0,1) 开始,设置:
low=0,high=1
- 不断读入原始数据的字符,找到这个字符所在的区间,比如 [ L, H ),更新:
low=low+(high−low)∗L high=low+(high−low)∗H
- 最后将得到的区间 [low, high)中任意一个小数以二进制形式输出即得到编码的数据。
乍一看这些数学和公式很难给人直观理解,所以我们还是看例子。例如有一段非常简单的原始数据:
ARBER
统计它们出现的次数和概率:
Symbol | Times | P |
---|---|---|
A | 1 | 0.2 |
B | 1 | 0.2 |
E | 1 | 0.2 |
R | 2 | 0.4 |
将这几个字符的区间在 [0,1) 上按照概率大小连续一字排开,我们得到一个划分好的 [0,1)区间:
开始编码,初始区间是 [0,1)。注意这里又用了区间这个词,不过这个区间不同于上面代表各个字符的概率区间 [0,1)。这里我们可以称之为编码区间,这个区间是会变化的,确切来说是不断变小。我们将编码过程用下图完整地表示出来:
<