一次与或非操作实战

2019-11-01  本文已影响0人  YocnZhao

文章背景

最近写了一次涉及与或非很多的逻辑:为了减轻网络数据量,我们接受丧失部分精度,需要把一堆float数据根据可以接受丧失精度的程度转成byte或者short,然后通过网络发出去,回来之后再转成float数组提供使用。所以是一个双向的转换操作。
之前一直对java中的int没什么概念,C/C++中有unsigned的概念,java中没有,所以导致java来做这种纯数据交换不涉及符号的操作的时候很费劲。
我们知道C++里面:

而java里面的byte也是占一个字节,相当于C++里面的char,范围是[-128,127],当然这是十进制的大小范围,转化成二进制后,这个大小应该怎么算呢?
带符号的数组,符号位在最高位,也就是说如果转化成二进制,负数是大于正数的。
十进制的大小顺序应该是[-128-> -1 -> 0 -> 127]
二进制的大小顺序应该是[0 -> 127 -> -128 -> -1]

int => 四个byte

一个int可以拆解成四个byte,直接右移强转就可以,强转成byte的时候会直接取低8位的数据。例子代码如下:

            int i;
            byte b0 = (byte) (i >>> 24);
            byte b1 = (byte) (i >>> 16);
            byte b2 = (byte) (i >>> 8);
            byte b3 = (byte) (i);
四个byte组合成一个int

四个byte组成int,需要注意的是byte的顺序,是按照大端还是小端存储。作为数据传输来讲,大端是比较合适的,如果用C++来写,大端就可以直接按照offest添加就可以了。
其实跟int拆解成4个byte思路是类似的。也是用 左移 + 与操作就可以实现。使用位移分别把4个byte放到对应的位置上,然后使用与操作拼成一个int。

            int x = b0 << 24 | b1 << 16 | b2 << 8 | b3 ;

假如 b0 = 59, b1 = 47, b2 = 123, b3 = 120;
b0 << 24 => 00111011 00000000 00000000 00000000
b1 << 16 => 00000000 00101111 00000000 00000000
b2 << 8 => 00000000 00000000 01111011 00000000
b3 << 0 => 00000000 00000000 00000000 01111000
x => 00111011 00101111 01111011 01111000
这样看起来是没有问题的,但如果b3的值不是120,而是 -120,我们再来看一下b3的二进制表示:
-120 => 11111111 11111111 11111111 10001000
问题就来了,如果有一个值是负数,高位的负数会冲掉原来与上的值。
所以我们需要下面这样的处理:

int x = b0 << 24 & 0xFF000000 | b1 << 16 & 0xFF0000 | b2 << 8 & 0xFF00 | b3 & 0xFF;
//或者是
int x_ = (b0 & 0xFF) << 24 | (b1 & 0xFF) << 16 | (b2 & 0xFF) << 8 | b3 & 0xFF;

只留下我们需要的位,其他的位都做成0,不影响结果就好。

float => byte | float => short

从一个归一化到0到1之间的float得到byte表示:

/**
     * 归一化的float 转化为byte
     */
    private static byte getByte(float f) {
        return (byte) (f * (Byte.MAX_VALUE - Byte.MIN_VALUE));
    }

    /**
     * 归一化的float转化为short,分解成两个byte
     */
    private static byte[] getShort(float f) {
        short s = (short) (f * (Short.MAX_VALUE - Short.MIN_VALUE));
        //右移8位获得高8位
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (s >> 8);
        //获得低8位
        bytes[1] = (byte) (s);
        return bytes;
    }
byte => float | short => float
short或者byte转回float:
/**
     * short转化为归一化的float
     */
    private static float getFloatFromShort(short t) {
        float f;
        int scope = Short.MAX_VALUE - Short.MIN_VALUE;
        if (t > 0) {
            //符号位为0,正数,直接除
            f = ((float) t) / scope;
        } else if (t < 0) {
            //符号位为1,负数,加Short.MIN
            f = ((float) t + scope) / scope;
        } else {
            f = 0;
        }
        return f;
    }

    /**
     * byte转化为归一化的float
     */
    private static float getFloatFromByte(byte b) {
        float f;
        int scope = Byte.MAX_VALUE - Byte.MIN_VALUE;
        if (b > 0) {
            //符号位为0,正数,直接除
            f = ((float) b) / scope;
        } else if (b < 0) {
            //符号位为1,负数,Byte.MIN
            f = ((float) b + scope) / scope;
        } else {
            f = 0;
        }
        return f;
    }
上一篇 下一篇

猜你喜欢

热点阅读