Elias gamma code 是一种用于正整数的通用编码,由Peter Elias发明。常被用于无法事先得知上界的正整数,即一种变长编码方式。
CocosBuilder的ccb文件中的整数正是采用了这种编码方式,被编码到了ccbi文件中(ccbi是二进制文件)。
在Cocos2dx引擎中,CCBReader利用了Elias gamma code 的解码方式,将ccbi文件中的整数解析出来。
有效位:一个二进制数从左往右第一个为1的位及其之后所有位叫有效位,其余称无效位,如:0 000 1 0001
floor:向下取整,即[X,X+1)区间中的所有数都取X;
我们都知道,int变量通常占4个字节(byte),每个字节8位(bit),共占32位,在计算机中以二进制存储。如果能剔除所有二进制数无效位,再将剩下有效位 紧密排列写进二进制文件里,就可以大大减少空间占用。这就是原理,很简单。
举个栗子:
剔除前:(17,11)10=(0000 0000 000 1 0001 ,0000 0000 0000 1011)2---->剔除后 (1 0001,1011)2
我们看到17的有效位个数为 5,无效位个数为27。11的有效位个数是 4,无效位个数是28。
然后对17和9剔除无效位,剔除后共占9位,剔除前,两个二进制数占了64位。
但是又考虑到解码时必须指明被编码了的有效位个数,不然解码器不知道应该读到哪一位为止。还要进行进一步处理,即在二进制数的 有效位 前 放置 [有效位个数-1] 个0,此时编码完成。
接着上面的例子,在17前加 4个0,在11前加 3个0。
(1 0001,1011)2---->编码结果:(0 000 1 0001, 000 1011 )2
最终,只用16位对原64位的两个数完成了编码。
为什么加的0要比有效位个数少 1 ? 跟解码原理有关。
解码时,从左往右读二进制串,一次读一位,边读边累计0的个数,记为 n 。当读到第一个有效位时,再继续往后读 n 位,即可完整读出一个整数的elias gamma编码。这正是 “在每个数的有效位前放置[有效位个数-1]个0” 的原因。
通过统计0的个数,解码器就能知道遇到第一个有效位后,还剩几个有效位要读。
看例子,编码后17和11的二进制码关于有效位对称,17和11的第一个有效位左右均是 n位:
(0 0001 0001, 000 1011)2
这样我们就能在二进制流中准确地读出一个又一个的elias gamma编码。读出编码后,再通过 或运算把编码的每一位映射到int变量的对应位上,即可还原该整数,完成解码。
前方介绍了通俗理解的编码过程。百度是这么描述的:
令N=floor(log~2~X),故 2^N^<=X<=2^N+1^;
输出N个0比特
接着输出X的二进制表示
读取并计数0比特直到第一个1比特出现,假设计数为N;
从第一个1比特之后,再读取 N 个比特,并将之还原成十进制正整数,令之为 M
最终解码为 2^N^+M
那要想对0进行编码怎么办? 我们可以在编码前进行加1处理,解码后再减1处理。
编码前,对整数+1,使0,1,2,3...->1,2,3,4...,再进行编码。
解码后,对所得整数-1,使 1,2,3,4...->0,1,2,3...,即可还原。
那要对有符号整数进行编码怎么办? 我们可以通过分段函数把有符号整数一一映射成正整数。
编码前,
对整数X>=0,进行映射X=2*X+1,使0,1,2,3...->1,3,5,7...
对整数X<0,进行映射X=-2*X,使-1,-2,-3...->2,4,6...
解码后,判断所得整数的奇偶性,利用函数,即可还原。