将4个整数打包成一个[10,10,10,2]整数

时间:2015-12-18 09:35:41

标签: java c++ bit-manipulation bitwise-operators bit-shift

我正在将C++ samples移植到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],此返回值为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]

到目前为止它是有道理的。现在我清理了左边的值,我想把它们拖到右边的右边。但是当我这样做的时候,左边的间隙填充了1s,我猜是因为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我感兴趣的位?

2 个答案:

答案 0 :(得分:7)

无符号右移运算符>>>将零移至最左侧位置。

来源:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

答案 1 :(得分:0)

    struct
    {
        int x : 10;
        int y : 10;
        int z : 10;
        int w : 2;
    } data;

此代码完全不可移植,即,如果它甚至可以在您当前的系统上按预期工作。

绝对没有办法告诉这个结构将包含什么。你不能知道什么是MSB,你不知道如何处理签名,你不能知道endianess,你不知道是否会有填充等等{ {3}}

唯一可移植的解决方案是使用原始uint32_t并将值移位到位。