我认为这并不是真正可能的,但还是值得问一下。假设我有两个小数(每个数的范围从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]。
我认为这并不是真正可能的,但还是值得问一下。假设我有两个小数(每个数的范围从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]。
使用位掩码相对容易些。思路是将一个字节分成更小的单元,并将它们分配给不同的元素。
对于两个数字,可以按如下方式:前4位为数字1,其余为数字2。您可以使用number1 = (x & 0b11110000) >> 4
,number2 = (x & 0b00001111)
来检索值,并使用x = (number1 << 4) | number2
来压缩它们。
对于两个数字,当然可以。每个数字有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
编辑:其他答案提到了每四位存储一个数字并使用位移的方法,这样更快。
一般来说,假设您想要混合 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
0-11的例子相对简单--每个数字可以用四位二进制数存储,因此将它们放入一个字节中只需要将其中一个左移4位,然后使用“或”运算符将两个数字合并即可。
四个大小相似的数字无法放入同一个字节中--每个数字四位二进制数乘以四个数字至少需要16位来存储。
@Mike Caron
你最后的例子(4个介于0-3之间的整数)使用位移运算要快得多。不需要使用floor()函数。
value = (a << 6) | (b << 4) | (c << 2) | d;
a = (value >> 6);
b = (value >> 4) % 4;
c = (value >> 2) % 4;
d = (value) % 4;
B = A1 + 12.(A2 + 12.(A3 + 12.A4))
A1 = B % 12
A2 = (B / 12) % 12
A3 = (B / 144) % 12
A4 = B / 1728
由于占用了2字节,因此从十二进制到(紧缩的)十六进制的转换显然更可取。
B1 = A1 + 256.A2
B2 = A3 + 256.A4
A1 = B1 % 256
A2 = B1 / 256
A3 = B2 % 256
A4 = B2 / 256
模数和除法是通过位掩码和移位实现的。
一个字节可以容纳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个数字。
由于一个字节是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
使用位掩码或位移操作。后者更快。
尝试一下二叉树,会很有趣的。(在开发中涉及数据和各种开发技巧方面,它将非常有用)