【发布时间】:2018-01-11 21:20:58
【问题描述】:
我需要压缩一大组(无符号)整数值,而目标是保持它们的相对准确性。简单来说,1,2,3的差别很大,1001,1002,1003的差别很小。
所以,我需要一种有损转换。自然的选择是建立一个对数刻度,但缺点是与它的转换需要浮点运算、log/exp 计算等。
OTOH 我不需要真正的对数刻度,我只需要它在某种意义上类似于它。
我想出了一个以浮点方式编码数字的想法。也就是我为每个压缩数分配N个比特,其中有的代表尾数,剩下的代表序数。尾数大小和顺序的选择取决于所需的范围和精度。
我的问题是:这是个好主意吗?或者也许存在更好的编码方案 w.r.t.计算复杂度与质量(类似于对数刻度)。
我具体实现了什么:
正如我所说,尾数和顺序位。顺序位领先,因此编码的数字越大 - 原始数字越大。
实际数字是通过在尾数(也称为隐式位)后附加一个额外的前导位并按编码顺序左移来解码的。最小的解码数字是1 << M,其中M 是尾数的大小。如果所需的范围应该从 0 开始(就像我的情况一样),那么可以减去这个数字。
编码数字也很简单。添加1 << M,然后找到它的顺序,即它应该右移多少,直到它适合我们的带有隐式前导位的尾数,然后编码是微不足道的。查找订单是通过中值搜索完成的,结果只有几个ifs。 (例如,如果有 4 个 order bits,则最大 order 为 15,并且在 4 ifs 之内找到)。
我称之为“准对数”刻度。数字越大,绝对精度越低。但与真正的对数尺度不同,其中粒度连续增加,在我们的例子中,它在每个固定大小范围后跳跃 2 倍。
这种编码的优点:
- 快速编码和解码
- 没有浮点数,在处理它们、边界情况等过程中没有隐式精度损失。
- 不依赖于标准库、复杂数学函数等。
- 编码和解码可以通过 C++ 模板实现,因此转换甚至可以在编译时中实现。这很方便以人类可读的方式定义一些编译时常量。
【问题讨论】:
标签: algorithm encoding compression logarithm