如何将三个 4 位带符号整数(即 5 位)打包成一个 16 位整数?
How do you pack three 4 bit signed integers (so 5 bits) into a single 16 bit integer?
我想将 3 个带符号的 4 位整数(4 位数据,1 位符号位)打包成一个 16 位整数,但我不知道该怎么做或从哪里开始:(
我需要它用尽可能少的数据来表示 3D 网格中的位置(因为网格尺寸越大,它真的会加起来)。如果有帮助,我正在使用 GLM(OpenGL 数学库,所以我可以访问 glm::sign()
)
等函数
如果可能,请给我打包和解压的代码。
谢谢
@JDługosz 如果您在支持该结构语法的平台上,那么答案很好。但是,您提到了 OpenGL。
这是一个可以在着色器中运行的版本。
基本上,以与平台无关的方式测试符号,为此设置一个位(1 表示负数,0 表示正数),添加要打包的 int
的低四位,然后将结果移动五位以为下一个值腾出空间。
由于您处理的是从 -15 到 +15 的值,您可以稍微简化一下。而不是检查符号,只需向值添加一个常量以强制它为正。 (不过,我建议在打包端添加一个 assert
以确保输入值实际上适合 4 位。)解包时,减去该常量。
TL;DR: 将你的输入转换为正整数,抓取低 5 位,然后 mask/shift/add.
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
或适用于您的着色器模型和语言的等效项。
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
将确保它确实按照您的意图进行,所有字段仅使用一个词。我听说过的所有用于传统平台的编译器都会按预期打包。
我想将 3 个带符号的 4 位整数(4 位数据,1 位符号位)打包成一个 16 位整数,但我不知道该怎么做或从哪里开始:(
我需要它用尽可能少的数据来表示 3D 网格中的位置(因为网格尺寸越大,它真的会加起来)。如果有帮助,我正在使用 GLM(OpenGL 数学库,所以我可以访问 glm::sign()
)
如果可能,请给我打包和解压的代码。
谢谢
@JDługosz 如果您在支持该结构语法的平台上,那么答案很好。但是,您提到了 OpenGL。
这是一个可以在着色器中运行的版本。
基本上,以与平台无关的方式测试符号,为此设置一个位(1 表示负数,0 表示正数),添加要打包的 int
的低四位,然后将结果移动五位以为下一个值腾出空间。
由于您处理的是从 -15 到 +15 的值,您可以稍微简化一下。而不是检查符号,只需向值添加一个常量以强制它为正。 (不过,我建议在打包端添加一个 assert
以确保输入值实际上适合 4 位。)解包时,减去该常量。
TL;DR: 将你的输入转换为正整数,抓取低 5 位,然后 mask/shift/add.
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
或适用于您的着色器模型和语言的等效项。
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
将确保它确实按照您的意图进行,所有字段仅使用一个词。我听说过的所有用于传统平台的编译器都会按预期打包。