美文网首页
一次与或非操作实战

一次与或非操作实战

作者: YocnZhao | 来源:发表于2019-11-01 15:51 被阅读0次

文章背景

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

  • char, 范围至少为 [-127 ~ 127] 。 (一般范围是 -128 到 127)
  • unsigned char, 范围至少为 [0 ~ 255]。

而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;
    }

相关文章

  • 一次与或非操作实战

    文章背景 最近写了一次涉及与或非很多的逻辑:为了减轻网络数据量,我们接受丧失部分精度,需要把一堆float数据根据...

  • Java中&与&&、|与||的区别与联系

    前言 Java中逻辑操作符有&&(与)、||(或)、!(非),按位操作符有&(与)、|(或)、~(非)、^(异或)...

  • 菜鸟学习javascript28 逻辑操作符

    逻辑操作符:非(not)、与(and)、或(or)。 逻辑非 逻辑非由一个叹号(!)表示,应用于任何类型。这个操作...

  • 布尔操作符——逻辑非

    布尔操作符共有3个:非(NOT)、与(AND)和或(OR) 逻辑非 逻辑非操作符首先会将它的操作数(在ECMASc...

  • PHP从入门到精通,050第四章PHP——PHP运算符:逻辑运算

    (六)逻辑运算符:与(&&)或(||)非(!) ①逻辑非(!): 非真即假,非假即真 ②逻辑与(&&):且 操作数...

  • Solidity变量类型

    布尔型 bool:值可以是true或false操作:!(逻辑非)&& (逻辑与,“and”)|| (逻辑或,“or...

  • Java运算符(逻辑运算)

    逻辑运算主要就是三类:与,或,非。范例:观察非的操作 在逻辑运算之中,最为麻烦的就是与和或两个操作,其各有两种写法...

  • 数字逻辑第二章

    与或非运算 与: 或: 非: 与非: 或非 与或非 异或 同或:(异或非) 逻辑代数公理和定律 重要规则 逻辑函数...

  • 007 图像像素的逻辑操作

    本节内容:每个像素点的位操作。常见的有与或非、异或、同或等。 与、或、异或是针对两张图像的位操作;还可以针对一张图...

  • grep、egrep、awk过滤多个关键字

    1、满足多个关键字(与操作) 2、满足任意关键字(或操作) 3、排除多个关键字(非操作) 4、其他操作

网友评论

      本文标题:一次与或非操作实战

      本文链接:https://www.haomeiwen.com/subject/jsotbctx.html