我正在尝试将此答案调整为任意数值。
假设我们有 3 个(无符号)数字:
v1
, v2
,v3
我们知道它们可能具有的各自最大值:
max1
, max2
, max3
.
max1 * max2 * max3 < 2^32
,
所以结果(打包值)在 32 位以内。
如何在没有“魔法”硬编码的情况下打包/解包它们?
我正在尝试将此答案调整为任意数值。
假设我们有 3 个(无符号)数字:
v1
, v2
,v3
我们知道它们可能具有的各自最大值:
max1
, max2
, max3
.
max1 * max2 * max3 < 2^32
,
所以结果(打包值)在 32 位以内。
如何在没有“魔法”硬编码的情况下打包/解包它们?
让数字按照与参考答案中相同的顺序打包,从右到左从 开始v1
:
v3 <- v2 <- v1
我们已经从引用的答案中获得了解决方案,但它仅适用于特定情况(源数据):
// packing:
packed = (v3 << 8) | (v2 << 7) | v1;
// unpacking:
v1 = packed & 0x7F;
v2 = (packed >> 7) & 1;
v3 = (packed >> 8);
上面的代码使用了以下魔法常量:
7
( size1
) - 分配第一个数字 ( v1
) 的位大小。
1
( size2
) - ...(类似地)对于第二个数字 ( v2
)。请注意,此常量在上面隐式使用:8 = 7 + 1
.
0x7F
( sample1
) - 用于按位比较以解压缩第一个数字 ( v1
) 的样本值。
1
( sample2
) - ...(类似地)对于第二个数字 ( v2
)。
为了得到一个通用的解决方案,概括上述常数就足够了。让我们分别将它们命名为size1
、size2
和。以下是它们的一般定义:sample1
sample2
size1 = Math.floor(Math.log(max1) / Math.log(2)) + 1;
size2 = Math.floor(Math.log(max2) / Math.log(2)) + 1;
sample1 = Math.pow(2, size1 + 1) - 1;
sample2 = Math.pow(2, size2 + 1) - 1;
因此,使用这些常量,一般解决方案应如下所示:
// packing:
packed = v3 << (size1 + size2) | v2 << size1 | v1;
// unpacking:
v1 = packed & sample1;
v2 = (packed >> size1) & sample2;
v3 = packed >> (size1 + size2);
这是一种稍微不同的方法。
int max1 = 1000;
int max2 = 500;
int max3 = 500;
移位值根据最大值的最高有效设置位确定。
int size1 = 32-Integer.numberOfLeadingZeros(max1);
int size2 = 32-Integer.numberOfLeadingZeros(max2);
int size3 = 32-Integer.numberOfLeadingZeros(max3);
通过对 -1 移位大小位进行补码确定的掩码值。
int mask1 = ~(-1<<size1);
int mask2 = ~(-1<<size2);
int mask3 = ~(-1<<size3);
int v1 = 934;
int v2 = 293;
int v3 = 349;
这里没有什么新东西。第二个班次同时改变第一个和第二个值。
int packed = (((v3<<size2)|v2)<<size1)|v1;
现在反转它
v1 = packed&mask1;
// this saves the shifted packed version for the next step
v2 = (packed = packed>>>size1)&mask2;
v3 = (packed>>>size2)&mask3;
System.out.println(v1);
System.out.println(v2);
System.out.println(v3);
印刷
934
293
349