熵編碼(四)-算術編碼(二)

尹佑壮發表於2024-08-03

目錄
  • 1. 前言
  • 2. 區間縮放背景
  • 3. 區間縮放原理
    • 3.1. 區間縮放基礎
    • 3.2. 區間縮放分析
  • 4. 區間縮放編碼

1. 前言

上篇文章熵編碼(三)-算術編碼(一)介紹了算術編碼的基本流程和工作原理。本篇文章主要講述算術編碼區間縮放

2. 區間縮放背景

上篇文章編碼過程使用的是無限精度的小數並且在編碼結束的時候再轉換成二進位制。然而由於計算機能處理的精度有限,許多編碼器使用的都是有限精度,從而導致編碼區間隨著編碼會越來越小直至為0,因此可編碼的字元數目受到編碼器的精度限制

3. 區間縮放原理

算術編碼區間範圍是[0, 1)的小數,但是暫存器只能儲存整數,因此暫存器儲存的是區間的小數部分[0x00000000...0U, 0xFFFFFFFF....FU),區間上下限有無限個0/1.然而暫存器位數有限, 實際只能儲存有限位數。
以32位暫存器為例,暫存器儲存的是[0x00000000U, 0xFFFFFFFFU),但可以假象在暫存器精度之後還有無限個0/1的字尾。每當暫存器的區間下限L高位被移除時,低位補0,暫存器的區間上限H高位被移除時,低位補1。這種方式可以使用有限精度模擬無限精度。

3.1. 區間縮放基礎

算術編碼過程永遠滿足三個不等式:

  1. 區間下限Low永遠單調遞增
  2. 區間上限High永遠單調遞減
  3. 區間上限High > 區間下限Low

滿足上述條件之後: 若High的最高位是0,此時Low的最高位也必定是0,那麼在之後的編碼過程中最高位不再變化;同理,若Low的最高位是1,此時High的最高位也必定是1,那麼在之後的編碼過程中最高位也不再變化。由於暫存器位數有限,為了最大化利用暫存器的位數編碼,因此當區間上下限的最高位相同時,將最高位移出暫存器並輸出,同時將區間上下限左移1位(透過上文可知下限補0,上限補1)。透過上述方法,我們可以充分利用暫存器的位數,也不會造成演算法錯誤。

3.2. 區間縮放分析

上文中區間上下限最高位相同移除暫存器同時低位補0或1,屬於區間縮放的兩種情況。區間縮放情況分為一下三種(n是區間精度位數):

  1. 當Low最高位為1時,Low > Middle,由於High > Low永遠成立,因此High的最高位也是1, 此時的小數區間是[0。5, 1),用二進位制表示區間是0.1x。此時可以將High和low的最高位都移出並輸出,即左移1位,同時低位補0或1:

    Low = (low - 2n-1) << 1
    High = ((High - 2n-1) << 1) | 1
  2. 當High最高位為0時,High < Middle,由於High > Low永遠成立,因此Low的最高位也是0,此時的小數區間是[0, 0.5),用二進位制表示區間是0.0x。此時可以將High和low的最高位都移出並輸出,即左移1位,同時低位補0或1:

    Low = Low << 1
    High = (High << 1) | 1
  3. 當High最高兩位是“10”,Low最高兩位是“01”,此時的小數區間是[0.25, 0.75), 用二進位制表示區間是0.01x或者0x10x。此時將High和Low的此高位移出,最高位不變,低位補0或1, 並且記錄次高位移出次數cnt。在之後的編碼過程中,遇到第一種區間縮放,輸出一個0和cnt個1;遇到第二種區間縮放輸出一個1和cnt個0

    Low = (low - 2n-2) << 1
    High = ((High - 2n-2) << 1) | 1

4. 區間縮放編碼

以上篇文章編碼示例為例,初始小數編碼區間是[0, 1)。因為暫存器儲存小數部分,因此暫存器編碼區間是[0, 256)。下文編碼過程描述的編碼區間變化是暫存器編碼區間變化,對應的小數編碼區間變化不做描述,僅在最後輸出編碼結果的時候輸出對應小數結果
舉例:輸入序列"aabbc", 符號機率如下表:

symbol a b c
probability 0.4 0.4 0.2

1.算術編碼會根據機率分割初始編碼區間[0,256), 其中區間的下限為表中前面的符號的累計機率

a:[0, 102), b:[102, 205), c:[205, 256)

字元序列第1個字元a,那麼編碼區間是[0, 102)。二進位制區間[00000000b, 01100110b),區間縮放:輸出一個“0”,最高位移出一位,縮放後二進位制區間[00000000b, 11001101),編碼區間是[0, 205)

2.按照字元機率重新劃分[0, 205)編碼區間

a:[0, 82), b:[82, 164), c:[164, 205)

字元序列第2個字元a,那麼編碼區間是[0, 82)。二進位制區間[00000000b, 01010010b), 區間縮放:輸出一個“0”,最高位移出一位,縮放後二進位制區間[00000000b, 10100101b),編碼區間是[0, 165)

3.按照字元機率重新劃分[0, 165)編碼區間

a:[0, 66), b:[66, 132), c:[132, 165)

字元序列第3個字元b,那麼編碼區間是[66, 132)。二進位制區間[01000010b, 10000100b), 區間縮放:記錄次高位次數cnt=1,次高位移出,縮放後二進位制區間[000000100b, 10001001b),編碼區間是[4, 137)

4.按照字元機率重新劃分[4, 137)編碼區間

a:[4, 57), b:[57, 110), c:[110, 137)

字元序列第4個字元b,那麼編碼區間是[57, 110)。二進位制區間[00111001b, 01101110b), 區間縮放:輸出一個“0”,次高位移出次數cnt=1個“1”,最高位移出一位,縮放後二進位制區間[01110010b, 11011101b),編碼區間是[114, 221)

5.按照字元機率重新劃分[114, 221)編碼區間

a:[114, 157), b:[157, 200), c:[200, 213)

字元序列第5個字元c,那麼編碼區間是[200, 213)。二進位制區間[11001000b, 11010101b), 區間縮放:輸出兩個“1”,一個“0”,最高位移出三位,縮放後二進位制區間[01000000b, 10101000b),編碼區間是[104, 171)

快取二進位制0001110,最終的編碼二進位制低位補1得到結果是00011101,表示的小數是0.00011101(0.11328125)。可以看到算術編碼使用區間縮放得到的編碼結果和上篇文章使用無限精度小數得到的結果是一致的。說明編碼方法是符合預期的,並且僅使用了8位bit實現了算術編碼。使用區間縮放的算術解碼流程就不敘述了,感興趣的同學可以自己推導

總結:算術編碼使用區間縮放可以使用有限精度位數實現算術編碼,因此實際應用中算術編碼演算法都會使用區間縮放

相關文章