最近在补习Java基础,位移运算是今天的主角。
在此之前我们要先来复习下计算机二进制的一些概念。
在计算机硬件的世界里,芯片,处理器等所处理的电信号都为高低电平,即为10信号。
顺接上篇的一个概念来讲下:字节(byte)
1 byte = 8bit(位) 也就是一个字节相当于8位(0000 0000)
如果是两个字节那就是16位 0000 0000 0000 0000
计算机里的数也分有符号数跟无符号数, 有符号数的最高位表示符号正0/负1, 而无符号数的最高位跟其他位一样表示实际的数。
今天只说有符号数:
正数:即最高位为0,比如 0000 0001 为 1
负数:最高位为1, 比如 1000 0011 为 -3
这二进制是怎么算成我们生活中常用的十进制数呢?
1000 0011 = 去掉最高位的1(符号-),剩下的从右往左依次是以2为底数,从0开始间隔为1的幂数
上面的计算是 -(2^0+2^1) = -3
所以 8位有符号数的范围是[-127, 127]
1111 1111 = -(2^0+2^1+2^2+2^3+2^4+2^5+2^6) = -127
0111 1111 = 2^0+2^1+2^2+2^3+2^4+2^5+2^6 = 127
上面的正数负数皆为我们我们容易理解的写法。在计算机里,正数以其原码,负数以其补码计算。
原码,反码,补码:
正数的原码、反码、补码皆为其本身;
负数的原码是其本身,
负数的反码: 最高位(符号位不变),其余全部取反, 0变1, 1变0, 1000 0011(原码) => 1111 1100(反码)
负数的补码: 反码的基础上加1,这里有个注意点是,二进制是逢2进1.
1000 0011(原码) => 1111 1100(反码) => 1111 1101(补码)
讲完了上面的基础,正是进入正题,位移运算,顾名思义:位置的移动运算;
左移:正数负数都在右侧补0,负数最高位不变
右移:正数补0, 负数最高位不变,空位补1
下面有段Java的位移运算代码:
public static void main(String[] args) {
System.out.println(6 >> 2);
System.out.println(-8 << 3);
System.out.println(-9 >> 1);
}
运算结果如下:
1
-64
-5
先来算第一个: 6 >> 2
6的二进制为: 0000 0110 = 2^1+2^2 = 6
往右移2位,0000 0001 = 2^0 = 1
接着来算第二个:-8 << 3
-8的二进制: 1000 1000 = -(2^ 3) = -8
负数以补码形式计算: 1111 0111(反码) => 1111 1000(补码)
最高位(符号位)不动,其余向左移动3位,空位补0, 1001 0000 移动后的依旧为补码,我们需要还原为原码:
1100 0000 减1 => 1011 1111 取反 => 1100 0000 = -(2^6) = -64
然后算第三个:-9 >> 1
-9的二进制: 1000 1001 = -(2^0+2^3) = -9
负数以补码运算: 1111 0110(反码)加1=> 1111 0111
最高位不动, 其余位向右移动1位, 空位补1, 1111 1011(补码)
1111 1011 减1 => 1111 1010 取反 => 1000 0101 = -(2^0+2^2) = -5
至此,例子解析完毕,有问题请指教。