【问题标题】:Semi-random data sorted compression issue半随机数据排序压缩问题
【发布时间】:2013-01-18 05:27:23
【问题描述】:

我有this 排序的整数数字序列。

它们之间的差异是随机的。但是,如果您计算每个变量的差异,您会发现它看起来有点与随机数/函数相关的对数函数(差异以对数方式增加)。

我知道这不是一个庞大的数字,但我有成千上万个这样的系列(由相同的算法生成)。

我正在尽可能地压缩这些数据。我主要玩 delta 压缩,只能将数据压缩到原始大小的 30%。

【问题讨论】:

    标签: random compression


    【解决方案1】:

    (由相同算法生成)

    那么该算法本身可能提供最佳压缩。这是什么?

    除此之外,很容易将数据减少到大约 10K 字节。用可变长度整数编码差异。这样的整数表示为高位等于 1 的字节序列(任何数量的字节,包括无),后跟一个高位等于 0 的字节。然后连接每个字节的低七位得到整数。最低有效位在前。

    这具有将小于 128 的所有值编码在单个字节中的优点。超过 96% 的差异小于 128。然后,通用压缩器将有效地对这些字节进行 Huffman 编码。

    将其应用于您的差异,然后使用 gzip -9 压缩,我得到 10626 字节。强制 gzip 算法仅使用 Huffman 压缩,我得到 10018 字节。如果我在第一个高位等于 1 之前剪切文件,仅使用 Huffman 分别压缩这两个部分,然后将它们组合起来,我得到 9701 个字节。

    更新:

    这里是生成和解码变长整数的代码:

    /* Write n as a variable-length integer to out. */
    void var(unsigned long n, FILE *out)
    {
        int ch;
    
        do {
            ch = (int)(n & 0x7f);
            n >>= 7;
            if (n)
                ch += 0x80;
            putc(ch, out);
        } while (n);
    }
    
    #define ULBITS 64   /* set to the number of bits in an unsigned long */
    
    /* Read a variable-length integer from in, putting it in *n.  Return 0 on
       success, -1 on immediate end-of-file, -2 if end-of-file in the middle of an
       integer, or 1 on overflow of the unsigned long type. */
    int unvar(unsigned long *n, FILE *in)
    {
        int ch, b;
        unsigned long d;
    
        *n = 0;
        b = 0;
        do {
            ch = getc(in);
            if (ch == EOF)
                return b ? -2 : -1;
            if (b >= ULBITS)
                return 1;
            d = (unsigned long)(ch & 0x7f) << b;
            if ((d >> b) != (ch & 0x7f))
                return 1;
            *n += d;
            b += 7;
        } while (ch & 0x80);
        return 0;
    }
    

    【讨论】:

    • 用变长整数编​​码差异的算法叫什么名字?
    • 直到我刚刚在谷歌上搜索过,我才知道。在那之前,我会称它为“明显的可变长度整数格式”。然而它被称为可变长度量的 VLQ,并且显然首先出现在 MIDI 中。见en.wikipedia.org/wiki/Variable-length_quantity。然而,当我实现它时,我以小端顺序而不是大端顺序来执行它,正如维基百科文章所描述的那样。小端更简单。
    • 谢谢!你的实现是开源的吗?如果是,我在哪里可以找到它?
    • 变长整数的实现很简单。我会将其添加到答案中。
    【解决方案2】:

    当前存储的文件大小为 101 KB。

    如果您将文件存储为 32 位整数序列(以二进制形式 - 是的,它们都足够小,可以执行此操作),那么您的大小将降至 57 KB(14,345 个整数 x 4 字节)。 gzipping 会为您提供 21 KB 的文件。这已经超过了 30% 的界限,但我们可以做得更好!

    如果您将每个连续的差异存储为 32 位整数,则 gzip 压缩到 15 KB。

    如果你想避免 gzip,我们可以拿出一些花哨的技巧。对每个差异使用简单的Elias gamma coding 会生成一个 14 KB 的文件。不过,这需要一个烦人的比特流读取器/写入器,这可能是一种关闭。

    通过适当调整的exp-Golomb code,您可能会做得更好;我没试过。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-22
      • 2011-05-21
      • 2021-09-25
      • 2015-05-05
      • 2011-03-10
      • 1970-01-01
      • 2011-11-12
      • 1970-01-01
      相关资源
      最近更新 更多