【问题标题】:Compression by quazi-logarithmic scale准对数尺度压缩
【发布时间】: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


    【解决方案1】:

    在您的压缩算法中,每组在压缩后产生相同输出的数字将被解压缩到该组中的最低数字。如果将其更改为中间的数字,则平均故障将减少。

    例如对于 8 位尾数和 5 位指数,[0x1340, 0x1350) 范围内的数字将由decompress(compress(x)) 转换为0x1340。如果首先压缩整个范围,然后再解压缩,则总差值为 120。如果输出为 0x1348,则总误差仅为 64,从而将误差减少了 46.7%。因此,只需在输出中添加2 << (exponent - 1) 即可显着降低压缩方案的误差。

    除此之外,我认为这个方案没有太大问题。请记住,您将需要 0 的特定编码。会有其他编码,但在不了解输入的任何具体内容的情况下,这将是您可以获得的最佳编码。

    编辑:
    虽然可以将结果的校正从解压缩移动到压缩步骤,但这会增加将指数范围扩大一倍的成本。这是因为对于设置了 MSB 的数字,只有一半的数字将使用相应的指数(另一半将由设置了第二高位的数字填充)。设置了 MSB 的数字的高半部分将按次高的顺序排列。

    所以例如对于仅用 15 位尾数编码的 32 位数字,直到 0x8FFF FFFF 的数字的阶数为 15(尾数 = 0x1FFF 和指数 = 15)。所有较高值的​​阶数为 16(尾数 = 0x?FFF 和指数 = 16)。虽然指数增加 1 本身看起来并不多,但在这个例子中,它已经为指数增加了额外的位。

    此外,上述示例的解压步骤会产生整数溢出,这在某些情况下可能会出现问题(例如,如果在checked-mode 中完成解压,C# 会抛出异常)。同样适用于压缩步骤:除非处理得当,否则将 2^(order(n) - 1) 添加到输入 n 将导致溢出,从而将数字按 0 顺序排列。

    我建议将更正移至解压缩步骤(如上所示),以消除潜在的整数溢出作为问题/错误的来源,并保持需要编码的指数数量最少。

    EDIT2:
    这种方法的另一个问题是,当对压缩进行校正时,一半的数字(不包括最低阶)最终形成一个更大的“组”,从而降低了精度。

    【讨论】:

    • 好点,谢谢。实际上,我以一种不同的方式处理它:在编码期间,我将数字四舍五入为更接近的“整数”。如果订单不为零,那么我将在右移之前将“一半”添加到数字。
    • @valdo 所以你基本上实现了我在压缩步骤而不是解压缩上建议的步骤。这会起作用,但会将需要编码的指数数量增加一。我将对此进行解释。
    • 我明白你的意思。但我也解决了这个特定问题。我确定可以编码的最大原始数字(编码数字没有溢出),并且在编码期间我自动截断它。与您的建议相比 - 可以说具有相同编码的“集群”被移动到更大的一侧。好吧,无论如何,非常感谢。我认为这种“准对数编码”的整个想法对您来说似乎很好,对吧?
    • @valdo 是的,准对数编码很好,基本上是你能得到的最好的。但我真的建议将校正移至减压。我还注意到在压缩时精度会降低——虽然有点晚了。
    猜你喜欢
    • 2011-05-09
    • 1970-01-01
    • 2021-10-11
    • 2023-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-03
    相关资源
    最近更新 更多