将多个值打包成一个整数

4

假设我有几个变量,比如苹果,橙子和香蕉。

我有8个苹果,1个橙子和4个香蕉。

是否可以将这些值转换为单个整数,并根据计算出的整数值恢复它们的原始值?

我在网上找到了一个例子。

int   age, gender, height;
short packed_info;
. . .
// packing
packed_info = (((age << 1) | gender) << 7) | height;
. . .
// unpacking
height = packed_info & 0x7f;
gender = (packed_info >>> 7) & 1;
age    = (packed_info >>> 8);

但是当我输入随机数字时,它似乎不能像应该的那样工作。

5个回答

13

如何实现这个

是的,你可以实现这个。最简单的方法就是当前你正在做的,即将整数的不同位分配给不同的值。对于32位整数来说,你正在做的可能类似于:

|3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1     |      |             |
|1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 |  7   |6 5 4 3 2 1 0|
|                     Age                        |Gender|   Height    |
当你将一个数值右移八位进行位操作时,你只获取到了这个数字的年龄位。如果你将这个数值右移七位,并使用掩码1(即value >>> 7 & 1),那么你就可以得到性别信息。如果你只是从底部七位中获取信息(即value & 0x7F),那么你就可以得到身高信息。 为什么它容易出问题 你的示例缺少一些重要的内容:值的范围。例如,身高值永远不可能超过127。如果你尝试存储128或更高的身高值,那么现在的写法将导致身高的一部分覆盖性别信息,因为你需要八位来存储这么大的值。这就是为什么随机数不起作用的原因。
同样地,如果有人不小心输入了不是0或1的性别信息,那么它将破坏年龄值的某一部分,因为你无法在单个位中存储这么高的数值。
在赋值中修复这个问题的方法是通过添加位掩码,像这样:

packed_info = (((age << 1) | (gender & 1)) << 7) | (height & 0x7f);

这种做法可以确保性别不会覆盖年龄,身高也不会覆盖其他信息。但是,如果输入的身高大于127,它将对127取模后再使用。

通常为什么不建议这样做

因为这容易出现错误,而且整数占用的内存并不多。你不能只记住它是一个int,还需要记住位布局的样子。保持三个int更容易。

然而,在传输速度很重要的情况下,仍然会使用这种方法。例如数字电视或其他视频、数字音频、以太网协议等。


3

您可以打包和解包有符号的值。例如,将两个整数打包在一起:

int pack2(int val1, int val2)
{
    int ret_val = (((val1 & 0xFFFF) << 16) | (val2 & 0xFFFF));
    return ret_val;
}

int[] unpack2(int packed)
{
    int val1 = ((packed >> 16) & 0xFFFF);
    // restore sign
    if ((val1 & 0x8000) != 0)
        val1 |= 0xFFFF0000;

    int val2 = (packed & 0xFFFF);
    // restore sign
    if ((val2 & 0x8000) != 0)
        val2 |= 0xFFFF0000;

    return new int[] { val1, val2 };
}

当然,你必须确保这两个值都在-0x7FFF和0x7FFF之间(如果有两个值的话)。


2

首先,您的想法是正确的,但您的移位操作可能不正确。

尽管这更像是一个数学问题而不是Java问题,但我们还是来讨论一下吧 :)

实际上,您可以使用以下方法将任意数量的整数打包成单个整数,假设这些整数可以无限增长:

(令n为结果数字,n1...nk为数字,Pn为第n个质数)

n = 2^n1 + 3^n2 + 5^n3 ... Pn^nk

现在这样做不行,因为解包很慢,而且你不能打包大数字或大量数字。无论采用什么技术,你都会遇到一个问题:数字越大,数量越多,打包就越困难。我想说的是,只要整数中实际上有足够的空间来容纳你的信息,你可以使用位打包或任何其他排序方式,你所使用的位逻辑将表现得非常好!

你好,感谢您的回复。 我该如何修改上面的解决方案,以便我可以最多保存100个值? - user303907

1

你可以做到,但这取决于目标整数的大小和“fruit”变量的可能范围。如果范围更大,则需要不同的位域配置。某个字段所需的位数等于log_2(最大范围值)。


1

这种打包方式是一种“约定俗成”。

以您的示例为例:

  • height 占用 7 位(从 0 到 127)
  • gender 占用 1 位(0 或 1)
  • age 占用剩余可用位数(如果是有符号的,则为 23 位,如果不是,则为 24 位,对于 Java 中的 int 类型)

    <-age-><-gender-><-height->

如果您使用随机数,很可能会溢出条目的有限大小(由“约定俗成”定义)。例如,如果您将 height 设置为 128,则会强制 gender 的 LSb(右侧位)为 1


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接