如何将三个4位有符号整数(即5位)打包成一个16位整数?



我想将3个有符号的4位整数(4位数据,1位符号位)打包成一个16位整数,但我不知道如何做到这一点或从哪里开始:(

我需要用尽可能少的数据来表示3D网格中的位置(因为有了更高的网格尺寸,它真的加起来了)。如果它有帮助,我使用GLM (OpenGL数学库,所以我可以访问函数,如glm::sign())

如果可能的话,请给我打包的代码。

谢谢

struct s {
int16_t x : 5;
int16_t y : 5;
int16_t z : 5;
};
static_assert (sizeof(s) == sizeof(int16_t));

包装和拆包是自动的:就像使用任何其他struct。例如给定s val;,val.x=-17;包和foo(val.z);解包。

当你想把东西塞在一起以便在程序本身中使用时,这很好,但对于文档交换(如文件格式)则不适用,因为(如注释所指出的)它如何打包是实现定义的。

此外,static_assert将确保它确实做到了您想要的,所有字段只使用一个单词。我所听说过的所有用于传统平台的编译器都会按照预期进行打包。

@JDługosz的答案非常好,如果您在支持该结构语法的平台上。但是,你提到了OpenGL。

这是一个可以在着色器中工作的版本。

基本上,以平台无关的方式测试符号,为其设置一个位(1为负,0为正),添加您想要打包的int的低四位,然后将结果移动5位以为下一个值腾出空间。

由于您处理的是从-15到+15的值,因此可以稍微简化一下。而不是检查符号,只是添加一个常数的值,以迫使它是正的。(不过,我建议在打包端添加assert,以确保输入值实际上适合4位。)拆包时,减去该常数。

TL;DR:将您的输入转换为正整数,抓取低5位,并掩码/移位/添加。

int pack3 (int a, int b, int c)
{
a = (a + 16) & 0x1F;
b = (b + 16) & 0x1F;
c = (c + 16) & 0x1F;
return (a << 10) | (b << 5) | c;
}
void unpack3 (int p, int &a, int &b, int &c)
{ 
// The 3 mask & subtraction ops could be done in one step on P, but
// I left them separate here for something resembling clarity. 
c = (p & 0x1f) - 16;
b = ((p >> 5) & 0x1f) - 16;
a = ((p >> 10) & 0x1f) - 16;
}

对于着色器实现,unpack3()将需要用inout或等效的着色器模型替换&引用&语言。

在这里看到它与测试驱动程序一起工作。

最新更新