我想将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
或等效的着色器模型替换&
引用&语言。
在这里看到它与测试驱动程序一起工作。