算術符号のアイデアを用いた符号は色々あり、中にはアルゴリズムが公開されていないものもあります。 それらのうち、比較的簡単でかつ洗練されたものにJones符号があります。 Jones符号はオーストラリアの情報科学研究者C.B.Jonesによって、1981年に開発された算術符号です。 この符号では浮動小数点演算による丸めの誤差を避けるために、符号値を整数化し、符号化と復号化における演算処理を全て整数演算で行います。 符号値を整数化するために、まず元データに含まれる記号の出現率を出現頻度に置き換えます。
例えば4.1節の例で、元データに含まれる記号の出現頻度が、
となっていたとしますと、それぞれの記号に対応する半開区間は下図のように整数化されます。
この時、各記号に対応する半開区間の下限は、その記号の前の記号までの累積頻度となり、上限は下限にその記号の出現頻度を足したものになっています。 そしてこの整数化された半開区間を全記号数100で割りますと、本来の実数の半開区間になります。
次にaに対応する半開区間[0,40)をaからdまでの出現率で再分割するわけですが、まともに再分割しますと、当然、整数ではなくなってしまいます。 そこで、半開区間[0,40)をまた[0,100)と置き直して再分割します。 この時、aa〜adに対応する半開区間に変換率40/100をかけ、さらに全記号数100で割りますと本来の実数の半開区間になります。
このように、再分割を行うたびに分割する半開区間を全体の半開区間に置きなおし、その時の変換率を求めることにしておけば、理論的には全ての符号値を整数で表し、その値に変換率をかけて全記号数で割ることによって、本来の実数の符号値を計算することができるはずです。 しかしこの直接的な方法では、元データの記号数が多いと、変換率の計算や符号値の計算の時、数字の桁数が非常に大きくなってしまい効率的ではありません。
そこで全記号数の代わりに「スケールファクター」と呼ばれる仮の母数Nを導入し、各記号の出現頻度を全記号数がN個だった時の出現頻度に変換します。 スケールファクターNは最低出現頻度の変換後の出現頻度が1以上になるだけの大きさがあれば、つまり(全記号数/最低出現頻度)以上の大きさがあれば符号値の計算に利用することができます。 例えば前述の例では、N=100/10=10の時、最低出現頻度であるdの変換後の出現頻度が1となり、符号値を計算することが可能になります。
通常、元データは8ビットの固定長符号ですから、各記号がランダムに出現するとすれば平均出現率は1/256、つまりスケールファクターN=256程度で良いことになります。 しかし実際には各記号の出現頻度にバラツキがありますので、余裕をみてN=1000〜10000程度が比較的よく用いられるようです。 ここでは全記号数が多くありませんので、全記号数をそのままスケールファクターの値にし、N=100とすることにします。
ところがコンピュータ演算は普通は2進法で行いますので、スケールファクターの値によっては、本来の実数の符号値を計算する時に丸めの誤差が入ってしまうことがあります。 そこでスケールファクターの値Nから、
を満足するNに最も近い2の倍数2wを求めて、この値を修正スケールファクターN'とし、それを用いて符号値を計算することにします。 例えばN=100としますと、次のようになります。
この時、各記号の整数化した半開区間の境界値、つまりスケールファクターN当たりの各記号の累積頻度をFとしますと、修正スケールファクターN'当たりの修正累積頻度F'は、
F'=INT( | F ── N | +0.5)=INT( | F ── 100 | ×128+0.5) |
となります。
頻度を四捨五入によって整数化しますと丸めの誤差が入りますが、この場合、修正頻度F'は必ず元の頻度よりも大きくなりますので、誤差は有効桁数以下の部分に入ることになり、復号化には差し支えありません。 この結果、各記号に対応する修正半開区間は下図のようになります。
この時、実数の符号値はF'/N'より、
51 ── 128 | =0.398475 | 90 ── 128 | =0.703125 | 115 ── 128 | =0.8984375 |
となり、本来の値とほんの少し異なることになりますが、その差異は有効桁数以下の部分で生じますので、やはり復号化には差し支えありません。
修正頻度F'をN'=2wで割るということは、2進法を用いるコンピュータ演算においては、2進数表現されたF'をwビットだけ右にシフトすることを意味します。 例えば、上記の51/128を2進法で計算しますと次のようになります。
51 ── 27 | = | 110011 ──── 1000000 | =0.0110011 |
またF'を仮数部(w+1)ビットの浮動小数点形式で表しますと、
51 ── 27 | = | 0.11001100×26 ──────── 27 | =0.11001100×2-1=0.01100110 |
となり、仮数部はそのままで指数部だけw減少します。 したがって2進法で計算した場合、F'をN'で割っても丸めの誤差は入らず、有効桁数は変わらないことになります。
次にaに対応する修正半開区間[0,51)を再分割する場合も、この区間幅をスケールファクターNに最も近い2の倍数に置き換えて再分割します。 ただしその値は、区間幅を約数として含んでいないと丸めの誤差が入る可能性がありますし、2wよりも小さな値ですと、再分割した場合の符号値が桁落ちして有効桁数が少なくなってしまいます。 またあまり大きくしすぎますと、符号値のビット数が多くなり効率的ではありません。 そこで、次のような条件を満足する値を選びます。
今の例ですと、
となり、この値H'=204が再分割の時の修正スケールファクター相当の値になります。
Hから実数の区間幅を求めるにはHをNで割りますが、H'はHを2m倍した値ですから、H'から実数の区間幅を求めるにはH'をN'×2m=2w×2m=2w+m=29で割ることになります。
この時、実数の符号値はF'/2w+mより次のようになります。
82 ── 512 | =0.1601562 | 143 ── 512 | =0.2792968 | 184 ── 512 | =0.359375 | 204 ── 512 | =0.3985375 |
この場合はF'を仮数部(w+m+1)桁の浮動小数点形式で表し、仮数部はそのままで、指数部だけ2w+m減少することに対応しますから、F'のビット長をm個増やせば、2w+mで割っても丸めの誤差は入らないことになります。
82 ── 512 | = | 0.1010010000×27 ───────── 29 | =0.1010010000×2-2=0.0010100100 |
つまりwは符号値の基本ビット数を規定する値であり、再分割をするたびに符号値の符号長がmビットだけ長くなります。 その際、
という条件より、区間幅Hが小さいほどmが大きくなり、符号値の増加ビット数が多くなります。 区間幅は対応する記号または語句の出現率に比例しますから、このことは出現率の大きな語句は短いビット列で符号化し、出現率の小さな語句は長いビット列で符号化することを意味します。 これは一種の正規化演算になっており、この方法を用いている限り、いくら演算を繰り返しても丸めの誤差が入らず、再分割を行うのに十分な精度が保証されることがJonesによって証明されています。 これがJonesによる前節の問題点2.の解決策です。