将 4 个整数打包成一个 [10,10,10,2] 整数
Packing 4 integers into one single [10,10,10,2] integer
我正在移植一些C++ samples to Java
我现在被困在尝试将四个整数打包成一个以位为单位的以下布局 [10, 10, 10, 2],即第一个 int 将占据前 10 位,第二个类似和第三个,而最后一个只是最后两位。
在 C++ 示例中,这是打包它们的代码:
GLM_FUNC_QUALIFIER uint32 packSnorm3x10_1x2(vec4 const & v)
{
detail::i10i10i10i2 Result;
Result.data.x = int(round(clamp(v.x,-1.0f, 1.0f) * 511.f));
Result.data.y = int(round(clamp(v.y,-1.0f, 1.0f) * 511.f));
Result.data.z = int(round(clamp(v.z,-1.0f, 1.0f) * 511.f));
Result.data.w = int(round(clamp(v.w,-1.0f, 1.0f) * 1.f));
return Result.pack;
}
Result.data是下面的struct
:
union i10i10i10i2
{
struct
{
int x : 10;
int y : 10;
int z : 10;
int w : 2;
} data;
uint32 pack;
};
输入等于 [-1f,-1f,0f,1f]
我们得到一个 Result.data
等于 [-511,-511,0,1]
和这个 return 值 1074267649,二进制是:
0 -511
| | | |
0100 0000 0000 1000 0000 0110 0000 0001
|| | |
1 -511
到目前为止我所做的是:
public static int packSnorm3x10_1x2(float[] v) {
int[] tmp = new int[4];
tmp[0] = (int) (Math.max(-1, Math.min(1, v[0])) * 511.f);
tmp[1] = (int) (Math.max(-1, Math.min(1, v[1])) * 511.f);
tmp[2] = (int) (Math.max(-1, Math.min(1, v[2])) * 511.f);
tmp[3] = (int) (Math.max(-1, Math.min(1, v[3])) * 1.f);
int[] left = new int[4];
left[0] = (tmp[0] << 22);
left[1] = (tmp[1] << 22);
left[2] = (tmp[2] << 22);
left[3] = (tmp[3] << 30);
int[] right = new int[4];
right[0] = (left[0] >> 22);
right[1] = (left[1] >> 12);
right[2] = (left[2] >> 2);
right[3] = (left[3] >> 0);
return right[0] | right[1] | right[2] | right[3];
}
tmp
是[-511,-511,0,1]
,left
是[-2143289344,-2143289344,0,1073741824]
,二进制是:
[1000 0000 0100 0000 0000 0000 0000 0000,
1000 0000 0100 0000 0000 0000 0000 0000,
0000 0000 0000 0000 0000 0000 0000 0000,
0100 0000 0000 0000 0000 0000 0000 0000]
到目前为止它是有道理的。现在我清除了左侧的值,我想将它们拖到右侧的正确位置。但是当我这样做时,我得到左边的空隙填充了 1,我猜是因为 java(?).
中的 signed int
那么right
就是[-511,-523264,0,1073741824]
或者:
[1111 1111 1111 1111 1111 1110 0000 0001,
1111 1111 1111 1000 0000 0100 0000 0000,
0000 0000 0000 0000 0000 0000 0000 0000,
0100 0000 0000 0000 0000 0000 0000 0000]
那么,为什么会发生这种情况,我该如何解决?也许只对我感兴趣的位进行 ANDing?
无符号右移运算符 >>>
将零移到最左边的位置。
来源:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
struct
{
int x : 10;
int y : 10;
int z : 10;
int w : 2;
} data;
此代码是完全不可移植的,也就是说,如果它甚至可以在您当前的系统上按预期工作。
您绝对无法判断此结构将包含什么。你不知道什么是 MSB,你不知道符号将如何处理,你不知道字节序,你不知道是否会有填充等。See this.
唯一可移植的解决方案是使用原始 uint32_t
并将值转移到位。
我正在移植一些C++ samples to Java
我现在被困在尝试将四个整数打包成一个以位为单位的以下布局 [10, 10, 10, 2],即第一个 int 将占据前 10 位,第二个类似和第三个,而最后一个只是最后两位。
在 C++ 示例中,这是打包它们的代码:
GLM_FUNC_QUALIFIER uint32 packSnorm3x10_1x2(vec4 const & v)
{
detail::i10i10i10i2 Result;
Result.data.x = int(round(clamp(v.x,-1.0f, 1.0f) * 511.f));
Result.data.y = int(round(clamp(v.y,-1.0f, 1.0f) * 511.f));
Result.data.z = int(round(clamp(v.z,-1.0f, 1.0f) * 511.f));
Result.data.w = int(round(clamp(v.w,-1.0f, 1.0f) * 1.f));
return Result.pack;
}
Result.data是下面的struct
:
union i10i10i10i2
{
struct
{
int x : 10;
int y : 10;
int z : 10;
int w : 2;
} data;
uint32 pack;
};
输入等于 [-1f,-1f,0f,1f]
我们得到一个 Result.data
等于 [-511,-511,0,1]
和这个 return 值 1074267649,二进制是:
0 -511
| | | |
0100 0000 0000 1000 0000 0110 0000 0001
|| | |
1 -511
到目前为止我所做的是:
public static int packSnorm3x10_1x2(float[] v) {
int[] tmp = new int[4];
tmp[0] = (int) (Math.max(-1, Math.min(1, v[0])) * 511.f);
tmp[1] = (int) (Math.max(-1, Math.min(1, v[1])) * 511.f);
tmp[2] = (int) (Math.max(-1, Math.min(1, v[2])) * 511.f);
tmp[3] = (int) (Math.max(-1, Math.min(1, v[3])) * 1.f);
int[] left = new int[4];
left[0] = (tmp[0] << 22);
left[1] = (tmp[1] << 22);
left[2] = (tmp[2] << 22);
left[3] = (tmp[3] << 30);
int[] right = new int[4];
right[0] = (left[0] >> 22);
right[1] = (left[1] >> 12);
right[2] = (left[2] >> 2);
right[3] = (left[3] >> 0);
return right[0] | right[1] | right[2] | right[3];
}
tmp
是[-511,-511,0,1]
,left
是[-2143289344,-2143289344,0,1073741824]
,二进制是:
[1000 0000 0100 0000 0000 0000 0000 0000,
1000 0000 0100 0000 0000 0000 0000 0000,
0000 0000 0000 0000 0000 0000 0000 0000,
0100 0000 0000 0000 0000 0000 0000 0000]
到目前为止它是有道理的。现在我清除了左侧的值,我想将它们拖到右侧的正确位置。但是当我这样做时,我得到左边的空隙填充了 1,我猜是因为 java(?).
中的 signed int那么right
就是[-511,-523264,0,1073741824]
或者:
[1111 1111 1111 1111 1111 1110 0000 0001,
1111 1111 1111 1000 0000 0100 0000 0000,
0000 0000 0000 0000 0000 0000 0000 0000,
0100 0000 0000 0000 0000 0000 0000 0000]
那么,为什么会发生这种情况,我该如何解决?也许只对我感兴趣的位进行 ANDing?
无符号右移运算符 >>>
将零移到最左边的位置。
来源:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
struct
{
int x : 10;
int y : 10;
int z : 10;
int w : 2;
} data;
此代码是完全不可移植的,也就是说,如果它甚至可以在您当前的系统上按预期工作。
您绝对无法判断此结构将包含什么。你不知道什么是 MSB,你不知道符号将如何处理,你不知道字节序,你不知道是否会有填充等。See this.
唯一可移植的解决方案是使用原始 uint32_t
并将值转移到位。