【问题标题】:Compress two or more numbers into one byte将两个或多个数字压缩为一个字节
【发布时间】:2010-08-17 04:56:59
【问题描述】:

我认为这不太可能,但无论如何都值得一问。假设我有两个小数字(每个数字的范围从 0 到 11)。有没有一种方法可以让我将它们压缩成一个字节,然后再将它们取回。用四个相似尺寸的数字怎么样。

我需要的是:a1 + a2 = x。我只知道 x 并从中得到 a1、a2
对于第二部分:a1 + a2 + a3 + a4 = x。我只知道 x 并从中得到 a1、a2、a3、a4
注意:我知道你不能取消添加,只是为了说明我的问题。

x 必须是一个字节。 a1, a2, a3, a4 范围 [0, 11]。

【问题讨论】:

  • 11 是二进制的 1011,所以它只需要 4 位。所以是的,这应该是可能的。您必须将其左移四次,然后添加它们。之后,要检索它们,获取前四位和后四位。
  • 这对我来说有点像家庭作业。
  • 不,我向你保证这是我自己的研究,学校要到 9 月才开学 ;-)
  • @Esteban,不,听起来更像是数据压缩。我也在数据压缩中遇到了这个问题,并解决了,看我的帖子。

标签: algorithm math


【解决方案1】:

这对于位掩码来说是微不足道的。想法是将字节分成更小的单元,并将它们专用于不同的元素。

对于 2 个数字,可以这样:前 4 位为 number1,其余为 number2。您可以使用number1 = (x & 0b11110000) >> 4number2 = (x & 0b00001111) 来检索值,并使用x = (number1 << 4) | number2 来压缩它们。

【讨论】:

  • 对于那些不熟悉移位的人:这只适用于可以用 4 位 (2 ^ 4) = 数字 0 - 15 表示的数字。原因是因为你在这里做的是存储一个值(以 4 位为单位),然后将它们移动 4 个位置并将下一个数字存储在该位置。由于一个字节只有 8 位,因此您只有两个 4 位数字的空间,因此这种方法仅限于小数字。
【解决方案2】:

当然,对于两个数字。每一个都有 12 个可能的值,所以这对总共有 12^2 = 144 个可能的值,这比一个字节的 256 个可能的值要少。所以你可以做例如

x = 12*a1 + a2
a1 = x / 12
a2 = x % 12

(如果你只有带符号的字节,例如在 Java 中,那就有点棘手了)

对于从 0 到 11 的四个数字,有 12^4 = 20736 个值,因此您无法将它们放在一个字节中,但您可以使用两个。

x = 12^3*a1 + 12^2*a2 + 12*a3 + a4
a1 = x / 12^3
a2 = (x / 12^2) % 12
a3 = (x / 12) % 12
a4 = x % 12

编辑: 其他答案是关于每四位存储一个数字并使用位移位。这样更快。

【讨论】:

  • 在这种特定情况下,移位更快,但我很欣赏这里的简单熵计算,因为它更通用:) 值得注意的是,移位是一种优化,只有在你确定有可能时才会应用成为一个解决方案。
【解决方案3】:

0-11 的例子非常简单——您可以将每个数字存储在 4 位中,因此将它们放入单个字节只需将一个 4 位向左移动,然后or将两者放在一起.

四个相似大小的数字不适合 - 每个四位乘以四给出至少 16 位来容纳它们。

【讨论】:

  • nitpick - 16 位不是保存 4 个数字 0-11 所需的最小位,您可以使用更少的位,但代价是无法快速编码/解码它们
  • @jk:嗯,是的,你可以用少于 16 个,但仍然需要超过 8 个。
【解决方案4】:

让我们笼统地说:假设你想混合 N 个数字 a1, a2, ... aN, a1 从 0..k1-1, a2 从 0..k2-1, ... 和 aN 从0 .. kN-1.

那么,编码后的数字是:

encoded = a1 + k1*a2 + k1*k2*a3 + ... k1*k2*..*k(N-1)*aN

然后解码变得更加棘手,逐步:

rest = encoded
a1 = rest mod k1
rest = rest div k1

a2 = rest mod k2
rest = rest div k2

...

a(N-1) = rest mod k(N-1)
rest = rest div k(N-1)

aN = rest # rest is already < kN

【讨论】:

    【解决方案5】:

    如果数字 0-11 的分布不均匀,您可以通过对常见值使用较短的位序列和对稀有值使用较长的位序列来做得更好。编码你使用的长度至少要花一点钱,所以有一个完整的 CS 分支致力于证明什么时候值得做。

    【讨论】:

      【解决方案6】:

      所以一个字节最多可以容纳 256 个值或十六进制的 FF。因此,您可以在一个字节中编码 0-16 的两个数字。

      byte a1 = 0xf;
      byte a2 = 0x9;
      byte compress = a1 << 4 | (0x0F & a2);  // should yield 0xf9 in one byte.
      

      如果你把它减少到只有 0-8 范围,你可以做 4 个数字。

      【讨论】:

      • "如果你把它减少到只有 0-8 的范围,你可以做 4 个数字。"嗯……也许是 0-3 范围?每个数字 2 位...4 个数字,8 位。
      【解决方案7】:

      由于单个字节为 8 位,因此您可以轻松地将其细分为更小的值范围。这种情况的极限是当你有 8 个单位整数时,称为位域。

      如果您想存储两个 4 位整数(每个整数为 0-15),您只需这样做:

      value = a * 16 + b;
      

      只要你做适当的边界检查,你永远不会在这里丢失任何信息。

      要取回这两个值,您只需这样做:

      a = floor(value / 16)
      b = value MOD 15
      

      MOD 是模数,是除法的“余数”。

      如果要存储四个 2 位整数 (0-3),可以这样做:

      value = a * 64 + b * 16 + c * 4 + d
      

      并且,让他们回来:

      a = floor(value / 64)
      b = floor(value / 16) MOD 4
      c = floor(value / 4) MOD 4
      d = value MOD 4
      

      我把最后一个分区留给读者练习;)

      【讨论】:

        【解决方案8】:

        @迈克·卡隆

        您的最后一个示例(0-3 之间的 4 个整数)使用位移位要快得多。不需要 floor()。

        value = (a << 6) | (b << 4) | (c << 2) | d;
        
        a = (value >> 6);
        b = (value >> 4) % 4;
        c = (value >> 2) % 4;
        d = (value) % 4;
        

        【讨论】:

          【解决方案9】:

          使用位掩码或位移位。后者更快

          测试二叉树以获得一些乐趣。 (它将在开发者生活中稍后处理有关数据和各种开发者的 voodom 哈哈)

          【讨论】:

            【解决方案10】:

            将四个值打包成一个数字至少需要 15 位。这不是一个字节,而是两个。

            您需要做的是将基数 12 转换为基数 65536,反之亦然。

            B = A1 + 12.(A2 + 12.(A3 + 12.A4))
            
            A1 = B % 12
            A2 = (B / 12) % 12
            A3 = (B / 144) % 12
            A4 = B / 1728
            

            因为无论如何这需要 2 个字节,所以从 base 12 到(打包的)base 16 的转换是迄今为止最好的。

            B1 = A1 + 256.A2
            B2 = A3 + 256.A4
            
            A1 = B1 % 256
            A2 = B1 / 256
            A3 = B2 % 256
            A4 = B2 / 256
            

            模数和除法是通过掩码和移位来实现的。

            【讨论】:

              【解决方案11】:

              0-9 更容易工作。您可以轻松地将 11 个随机顺序小数存储在 4 1/2 个字节中。这比 log(256)÷log(10) 压缩得更紧。只需通过创意映射。请记住,并非所有压缩都与字典、冗余或序列有关。

              如果您谈论的是随机数 0 - 9,则每 14 位可以有 4 位数字,而不是 15 位。

              【讨论】:

                猜你喜欢
                • 2014-01-16
                • 2011-03-26
                • 1970-01-01
                • 2013-04-21
                • 2018-04-01
                • 1970-01-01
                • 2019-03-24
                • 1970-01-01
                • 2012-09-08
                相关资源
                最近更新 更多