java移位运算符及负数的二进制表示

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38001814/article/details/87953506

前言

这段时间在看源码的过程中发现好多地方都用到了移位运算符,恰好这块知识又有点遗忘,所以借此机会顺便一起回顾下移位运算符以及由此延伸出来的知识点。

<<:带符号左移,低位补0,举例如下:

        // 正数的情况
        int t = 4;
        System.out.println(Integer.toBinaryString(t)); // 100
        t = t << 1;
        System.out.println(Integer.toBinaryString(t)); // 1000
        // 负数的情况
        int i = -1;
        System.out.println(Integer.toBinaryString(i)); // 11111111 11111111 11111111 11111111
        i = i << 1;
        System.out.println(Integer.toBinaryString(i)); // 11111111 11111111 11111111 11111110

Ps:针对左移还有个公式:x<<n = x*2^n,可以方便的计算出结果。

>>:带符号右移,正数高位补0,负数高位补1,举例如下

        // 正数的情况
        int t = 4;
        System.out.println(Integer.toBinaryString(t)); // 100
        t = t >> 1;
        System.out.println(Integer.toBinaryString(t)); // 10
        // 负数的情况
        int i = -1;
        System.out.println(Integer.toBinaryString(i)); // 11111111 11111111 11111111 11111111
        i = i >> 1;
        System.out.println(Integer.toBinaryString(i)); // 11111111 11111111 11111111 11111111

>>>:无符号右移,无论是正数还是负数,高位统统补0,举例如下

        // 正数的情况,可以看到正数的无符号右移与带符号右移得到的结果是一样的
        int i = 4;
        System.out.println(Integer.toBinaryString(i)); // 100
        i = i >>> 1;
        System.out.println(Integer.toBinaryString(i)); // 10
        // 负数的情况
        int i = -1;
        System.out.println(Integer.toBinaryString(i)); // 11111111 11111111 11111111 11111111
        i = i >>> 1;
        System.out.println(Integer.toBinaryString(i)); // 01111111 11111111 11111111 11111111

>>=:复合运算符,类似于+=,举例:a <<= 2 等价于 a = a << 2

Ps1:写到这里突然想起以前计算机课中一道作业题,问:2乘以8在计算机中最快的表达式是什么?反正当时最开始一会一脸懵逼,心想不就2 * 8嘛,还能有啥操作,其实就是为2 << 3速度最快,主要就是因为移位运算比起乘法运算少了很多开销,计算机底层是采用二进制运算,算术运算和逻辑运算,本质上算术运算也是通过与或非逻辑器件实现的。

Ps2:又想到一道很傻的关于+=的题,问:a = a + 1与a += 1的区别。其实就是前者的运算过程中要求a与1是同类型,而后者包含了隐性的强制类型转换,下面贴段代码可能印象更深刻。第一张图直接编译报错,由报错提示也很明显,右边表达式最后返回的是int类型,而左边是byte类型,由高精度转向低精度时会报错。

下面看+=,并不会出现任何报错信息也能顺利运行,这正是因为+=包含了隐性的强制类型转换,即b = (byte) (b+1)

        byte b = 2;
        b += 1;
        System.out.println(b); // 3

需要注意的是,任何语言都是没有<<<运算符的,因为左移都是逻辑位移,右移分为逻辑位移和算数位移,二进制数的符号位在最高位,而左移时只需在右边补0即可,不会产生符号问题,所以没有无符号左移的运算符必要。

负数的二进制表示

由于上面都是由编译器直接将数字转成二进制表示了,这里我一开始其实是忘记了负数的二进制是该如何表示,这里温故下负数的二进制表示

概念:负数的二进制表示是以原码的补码形式展现。

emm讲到这里先讲下计算机中原码、反码、补码的概念,先贴书上的阐述

原码表示法规定:用符号位和数值表示带符号数,正数的符号位用“0”表示,负数的符号位用“1”表示,数值部分用二进制形式表示。
反码表示法规定:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。
补码表示法规定:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1。

下面举例说明:

比如现有一个int类型的数字5,二进制表示为 00000000 00000000 00000000 00000101,(由于int类型占了4字节即32位,所以前面补了一堆0)这即是5的原码,正数的反码、补码均与原码相同,都为 00000000 00000000 00000000 00000101

而对于-5,先按其绝对值求原码得00000000 00000000 00000000 00000101,然后在最高位带上符号位即1,所以-5的原码为10000000 00000000 00000000 00000101,由于负数的反码是除最高位其余所有位统统取反,所以得-5的反码为:11111111 11111111 11111111 11111010,负数的补码是除最高位其余位取反之后再在最后一位+1即可,所以得-5的补码为:11111111 11111111 11111111 11111011 

到这里应该对负数的二进制表示很清楚啦~

猜你喜欢

转载自blog.csdn.net/m0_38001814/article/details/87953506