也许这个脚本可能有助于构建一个更好的算术编码器心智模型:gen_map.py。最初创建它是为了方便算术编码器库的调试并简化其单元测试的生成。然而,它创建了很好的 ASCII 可视化,也有助于理解算术编码。
一个小例子。假设我们有一个由 3 个符号组成的字母表:0、1 和 2,概率分别为 1/10、2/10 和 7/10。我们要编码序列[1, 2]。脚本将给出以下输出(暂时忽略 -b N 选项):
$ ./gen_map.py -b 6 -m "1,2,7" -e "1,2"
000000111111|1111|111222222222222222222222222222222222222222222222
------011222|2222|222000011111111122222222222222222222222222222222
---------011|2222|222-------------00011111122222222222222222222222
------------|----|-------------------------00111122222222222222222
------------|----|-------------------------------01111222222222222
------------|----|------------------------------------011222222222
==================================================================
000000000000|0000|000000000000000011111111111111111111111111111111
000000000000|0000|111111111111111100000000000000001111111111111111
000000001111|1111|000000001111111100000000111111110000000011111111
000011110000|1111|000011110000111100001111000011110000111100001111
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
001100110011|0011|001100110011001100110011001100110011001100110011
010101010101|0101|010101010101010101010101010101010101010101010101
前 6 行(==== 行之前)表示从 0.0 到 1.0 的范围,该范围以与符号概率成比例的间隔递归细分。注释第一行:
[1/10][ 2/10 ][ 7/10 ]
000000111111|1111|111222222222222222222222222222222222222222222222
然后我们再次细分每个区间:
[ 0.1][ 0.2 ][ 0.7 ]
000000111111|1111|111222222222222222222222222222222222222222222222
[ 0.7 ][.1][ 0.2 ][ 0.7 ]
------011222|2222|222000011111111122222222222222222222222222222222
[.1][ .2][ 0.7 ]
---------011|2222|222-------------00011111122222222222222222222222
注意,有些区间没有细分。当没有足够的空间来表示给定精度(由-b 选项指定)内的每个子区间时,就会发生这种情况。
每一行对应于输入中的一个符号(在我们的例子中 - 序列[1, 2])。通过跟踪每个输入符号的子间隔,我们将得到一个最终的间隔,我们想要用最少的比特进行编码。在我们的例子中,它是第二行上的第一个 2 子间隔:
[ This one ]
------011222|2222|222000011111111122222222222222222222222222222222
以下 7 行(==== 之后)表示相同的区间 0.0 到 1.0,但根据二进制表示法细分。每行都是一个输出,通过在 0 和 1 之间进行选择,您可以选择左半子间隔或右半子间隔。例如位 01 对应于第二行的子区间 [0.25, 05):
[ This one ]
000000000000|0000|111111111111111100000000000000001111111111111111
算术编码器的思想是输出位(0 或 1),直到相应的区间完全在(或等于)输入序列确定的区间内。在我们的例子中是0011。 ~~~~ 行显示了我们在哪里有足够的位来明确识别我们想要的间隔。
由| 符号组成的垂直线显示可用于对输入序列进行编码的位序列(行)的范围。