Revised : 2006/07/31
Since : 2006/07/31
説明を簡単にするために、全体を符号なし7bit(負は無)
レンジの精度を7bitとし最低確保する精度は3bitととする。(JAVAのbyte型を想定)
(通常はCPUが高速にあつかえる最大サイズがよい)
最低確保する精度とは、両隣と区別可能であること。つまり、頻度総数の最大値を保証するものである。
例としてabcabaを考える。
まず頻度表を作る。
出現頻度表 | |
文字 | 頻度 |
EOF | 1 |
c | 1 |
b | 2 |
a | 3 |
総数 | 7 |
これをレンジで表す。
R:幅
L:下限値
EOF:end of file
対応表 | |||
文字 | Low | Range | 備考 |
EOF | 6 | 1 | [6 , 7) |
c | 5 | 1 | [5 , 6) |
b | 3 | 2 | [3 , 5) |
a | 0 | 3 | [0 , 3) |
総数は7であり3bitで表せるから、ここから符号化を開始する。
区間は[low , low + range)と表せる。
初期の区間は[0 , 128)とする。
この時128は含まないためレンジは127とする。下限値は0である。
まず、現在のレンジを頻度総数で割り、一個あたりの幅を算出する。
入力文字の下限値に一個あたりの幅を掛け、増加分の下限値を算出し、現在の下限値に加算する。(新たな下限値)
入力文字の頻度に一個あたりの幅を掛け、新たなレンジを算出する。
以上を繰り返す。
low + rangeが5bit以下になった場合、レンジ拡大する。
通常7-5=2bitを作業領域とする。
拡大も下限値、幅とも2bit左シフト(4倍)する。lowの上位2bitは出力する。
low + rangeが5bit以下にならなくても、rangeが3bit以下になった場合はレンジ拡大する。
この時、rengeはlow下位5bitの2の補数とし、3bitより大きくなるまで拡大する。(桁上がりしないようにレンジ縮小)
abcabaの符号化について下表に示す。
R拡大 | 入力 | L算出 | low | 出力 | R算出 | range | ||||||||||||
R/総数 | 値 | L+R*入力のL | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 上位2bit | R*入力のR | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
初期値 | 初期値 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 初期値 127 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ||
127/7=18 | a | 0+18*0=0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 18*3=54 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | |
54/7=7 | b | 0+7*3=21 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 7*2=14 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | |
14/7=2 | c | 21+2*5=31 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2*1=2 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | |
Rを縮小 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2の補数 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |||
Rを拡大 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 00 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | |||
Rを拡大 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 11 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | |||
16/7=2 | a | 112+2*0=112 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 2*3=6 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | |
Rを拡大 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 11 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | |||
Rを拡大 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 10 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | |||
96/7=13 | b | 0+13*3=39 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 13*2=26 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | |
26/7=3 | a | 39+3*0=39 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 3*3=9 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | |
Rを拡大 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 01 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | |||
36/7=5 | EOF | 28+5*6=58 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 5*1=1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
よって出力符号は出力済み+最終下限値となる。
2進数表記すると00111110010111010となる。
次はこの00111110010111010を復号化する。
頻度表は符号化時と同じである。
区間は[low , low + range)と表せる。
初期のレンジは符号時と同じ127とする。
codeは符号語の上位7bitを読み込む。
まず、現在のレンジを頻度総数で割り、一個あたりの幅を算出する。
(code - low)を一個あたりの幅で割り、どの文字の区間に入るか判定する。(桁上がり判定のためlowも記憶する)
入力文字の下限値に一個あたりの幅を掛け、増加した分の下限値を算出する。
入力文字の頻度に一個あたりの幅を掛け、新たなレンジを算出する。
符号化と同判定でレンジ拡大する。
符号化時と同様に2bit左シフトするが、この時codeの下位2bitに符号語の次の2bitを読み込む。
以上を繰り返す。
上で符号化した00111110010111010について復号化を下表に示す。
R拡大 | 区間算出 | 出力 | L算出 | low | R算出 | range | 入力 | code | ||||||||||||||||||
R/総数 | (C-L)/R | 文字 | L+R*入力のL | 7 | 6 | 5 | 4 | 3 | 2 | 1 | R*入力のR | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 2bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
初期値 | 初期値 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 初期値 127 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 7bit | 0 | 0 | 1 | 1 | 1 | 1 | 1 | ||
127/7=18 | (31-0)/18=1 | a | 0+18*0=0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 18*3=54 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | ||||||||
54/7=7 | (31-0)/7=4 | b | 0+7*3=21 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 7*2=14 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | ||||||||
14/7=2 | (31-21)/2=5 | c | 21+2*5=31 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2*1=2 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ||||||||
Rを縮小 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2の補数 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |||||||||||
Rを拡大 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 00 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | ||||
Rを拡大 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 10 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | ||||
16/7=2 | (114-112)/2=1 | a | 112+2*0=112 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 2*3=6 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | ||||||||
Rを拡大 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 11 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | ||||
Rを拡大 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 10 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | ||||
96/7=13 | (46-0)/13=3 | b | 0+13*3=39 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 13*2=26 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | ||||||||
26/7=3 | (46-39)/3=2 | a | 39+3*0=39 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 3*3=9 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | ||||||||
Rを拡大 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 10 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | ||||
36/7=5 | (58-28)/5=6 | EOF |
よってabcabaが復号できた。
(当然であるが)符号化と復号化では幅とレンジ拡大のタイミングがおなじである。