位运算有符号右移,无符号右移和左移详解(应该算详细了)

位运算<<,>>,>>>讲解(应该算详细了)

使用位运算求整数绝对值之前我们先了解一下位运算中的<<,>>,>>>
有符号右移;>>
无符号右移;>>>
左移<<
左移是没有有符号的这一点在说到左移是会说明。
可能有些朋友到这里有些蒙圈,什么是有符号?左右移又代表什么呢?
至少在我的学校,身边的同学都对这个一脸蒙圈。。。

那么我们一个一个讲;
1;
首先我们把这四个位运算符分为两组;
有符号组;>>
和无符号组;>>>,<<
我们都知道计算机中的数据都是二进制存储的那么我们来一个例子来理解有符号组。如果理解了有符号组那么无符号组理解起来就会比较简单了。
我们定义一个16位的变量 num = 1
那么num用16位二进制表示为0000 0000 0000 0001
其中左边是高位,最左边的最高位为0代表这个数字是一个正数,若这个数字是1那么这个数将是个负数。而右边是低位。
如;num = -1
num用二进制表示为1111 1111 1111 1111(取反加补)最高位是1
在无符号左(右)移中无符号表示不考虑正负,有符号反之。

知道了这些我想我们可以来继续学习了!
2;
无符号右移>>> 不管正负右移后在高位补0
我们来具体说一下;
定义一个int num举例子来看看>>>到底做了啥

int num = 1;
System.out.println("输出num "+num);
System.out.println("输出num二进制"+Integer.toBinaryString(num));
System.out.println("输出num>>>1 "+(num>>>1));
System.out.println("输出num>>>1的二进制"+Integer.toBinaryString(num>>>1));
//输出结果
/*
输出num 1
输出num二进制 1
输出num>>>1 0
输出num>>>1的二进制 0
*/

输出时程序并未输出左边高位的0所以
num二进制 为0000 0000 0000 0000 0000 0000 0000 0001
num>>>1的二进制 为 0000 0000 0000 0000 0000 0000 0000 0000
我们可以理解num>>>1是2步完成了无符号右移
#1;先把num向右整体移动了一位
(我猜大家已经猜到了!没错!>>>后的数字代表移动位数!同理<<,>>,>>>后的数字都是移动位数。);
(移动后被后移的高位为空)000 0000 0000 0000 0000 0000 0000 0000 1(超出了32位被丢弃)
#2;之后在空高位补0
(补0)000 0000 0000 0000 0000 0000 0000 0000

那么如果num是负呢?
我们来看一下吧!

int num = -1;
System.out.println("输出num "+num);
System.out.println("输出num二进制 "+Integer.toBinaryString(num));
System.out.println("输出num>>>1 "+(num>>>1));
System.out.println("输出num>>>1的二进制"+Integer.toBinaryString(num>>>1));
/*
输出num -1
输出num二进制 11111111111111111111111111111111
输出num>>>1 2147483647
输出num>>>1的二进制 1111111111111111111111111111111
*/

我们依然像上面一样两步分析
#1;先把num向有整体移动了一位;
(移动后被后移的高位为空)111 1111 1111 1111 1111 1111 1111 1111 1(超出了32位被丢弃)
#2;之后在空高位补0
(补0)111 1111 1111 1111 1111 1111 1111 1111但因为打印时最左边的0并未打印出来所以为1111111111111111111111111111111。前面我们提到第一位是表示符号正负所以后面31位都为1也就是32位的最大取值0111 1111 1111 1111 1111 1111 1111 1111(十进制;2147483647)。

32位int 最大值 最小值
十进制 2147483647 2147483647
二进制 0111 1111 1111 1111 1111 1111 1111 1111 1000 0000 0000 0000 0000 0000 0000 0001

我们可以看到
num = -1
num>>>1 ;01111111111111111111111111111111
num = 1
num>>>1 ;0000000000000000000000000000
说明了无符号右移>>> 不管正负右移后都会在高位补0

知道了无符号右移我们就可以来说说有符号右移和左移了!
3;
很显然>>,>>>的区别是有无符号,相比>>>右移后的无脑补0,>>显然更聪明。在右移时它能判断正负,如果是正则高位补0,负补1;
我们来实际看一下

int num = 1;
System.out.println("num为正; ");
System.out.println("输出num "+num);
System.out.println("输出num二进制 "+Integer.toBinaryString(num));
System.out.println("输出num>>1 "+(num>>1));
System.out.println("输出num>>1的二进制 "+Integer.toBinaryString(num>>1));
/*
num为正; 
输出num 1
输出num二进制 1
输出num>>1 0
输出num>>1的二进制 0
*/

我们依然分两步来分析(输出时省略了高位的0)
#1;先把num向右整体移动了一位;
(移动后被后移的高位为空)000 0000 0000 0000 0000 0000 0000 0000 1(超出了32位被丢弃)
#2;之后因为是正数在空高位补0
(补0)000 0000 0000 0000 0000 0000 0000 0000
所以num>>1 = 0;
聪明的大家一定发现了,>>和>>>在正值时效果是一样的!都是右移后高位补0!事实也的确如此。

那么如果num为负呢?

int num = -1;
System.out.println("num为负; ");
System.out.println("输出num "+num);
System.out.println("输出num二进制 "+Integer.toBinaryString(num));
System.out.println("输出num>>1 "+(num>>1));
System.out.println("输出num>>1的二进制 "+Integer.toBinaryString(num>>1));

/*
num为负; 
输出num -1
输出num二进制 11111111111111111111111111111111
输出num>>1 -1
输出num>>1的二进制 11111111111111111111111111111111
*/

我们继续祖传两步分析;
#1;先把num向有整体移动了一位;
(移动后被后移的高位为空)111 1111 1111 1111 1111 1111 1111 1111 1(超出了32位被丢弃)
#2;之后因为是负数所以在空高位补1!很重要!
(补1)111 1111 1111 1111 1111 1111 1111 1111
所以num>>1 = -1;
这下就不一样了吧!哈哈

相对于>>,左移<<它的作用是左移并在低位补0且是无符号的。其实这也不难理解,向左移动本来就有可能改变正负所以左移也没有必要分出一个有符号了;
我们直接上实例!

int num = 1;
System.out.println("输出num "+num);
System.out.println("输出num二进制 "+Integer.toBinaryString(num));
System.out.println("输出num<<1 "+(num<<1));
System.out.println("输出num<<1的二进制 "+Integer.toBinaryString(num<<1));
/*
输出num 1
输出num二进制 1
输出num<<1 2
输出num<<1的二进制 10

祖传两步分析;
#1;先把num向左整体移动了一位;
0(超出舍去) 000 0000 0000 0000 0000 0000 0001
#2;之后因为是负数所以在空高位补1!很重要!
0000 0000 0000 0000 0000 0000 0010(补0)
所以num<<1 = 2;
负数同理就不分析了上个实例

int num = -1;
System.out.println("输出num "+num);
System.out.println("输出num二进制 "+Integer.toBinaryString(num));
System.out.println("输出num<<1 "+(num<<1));
System.out.println("输出num<<1的二进制 "+Integer.toBinaryString(num<<1));
/*
num为负; 
输出num -1
输出num二进制 11111111111111111111111111111111
输出num<<1 -2
输出num<<1的二进制 11111111111111111111111111111110
*/

最后总结一下<<,>>,>>>
有符号右移;>>
无符号右移;>>>
左移<<
int num = 1
num 二进制 0000 0000 0000 0000 0000 0000 0000 0001
输出num>>>1 的二进制 0000 0000 0000 0000 0000 0000 0000 0000
输出num>>1 的二进制 0000 0000 0000 0000 0000 0000 0000 0000
输出num<<1 的二进制 0000 0000 0000 0000 0000 0000 0000 0010
int num = -1
num 二进制 1111 1111 1111 1111 1111 1111 1111 1111
输出num>>>1的二进制 0111 1111 1111 1111 1111 1111 1111 1111
输出num>>1 的二进制 1111 1111 1111 1111 1111 1111 1111 1111
输出num<<1 的二进制 1111 1111 1111 1111 1111 1111 1111 1110

希望我的文章对大家有帮助。可能乍一看很多人不知道这样运算有什么用,下一次我来讲一下使用位运算实现Java中的Math.abs()方法。

你可能感兴趣的:(java,Java)