java位移运算符3 转

https://www.cnblogs.com/winsker/p/6728672.htmlhtml

移位运算符操做的对象就是二进制的位,能够单独用移位运算符来处理int型整数。java

理解java移位运算符
运算符 含义 例子
<< 左移运算符,将运算符左边的对象向左移动运算符右边指定的位数(在低位补0) x<<3
>> "有符号"右移运算 符,将运算符左边的对象向右移动运算符右边指定的位数。使用符号扩展机制,也就是说,若是值为正,则在高位补0,若是值为负,则在高位补1. x>>3
>>> "无符号"右移运算 符,将运算符左边的对象向右移动运算符右边指定的位数。采用0扩展机制,也就是说,不管值的正负,都在高位补0. x>>>3

 

 

 

 

 

 

 

 

 

 

 

以int类型的6297为例,代码以下:面试

1 System.out.println(Integer.toBinaryString(6297));   
2 System.out.println(Integer.toBinaryString(-6297));   
3 System.out.println(Integer.toBinaryString(6297>>5));   
4 System.out.println(Integer.toBinaryString(-6297>>5));   
5 System.out.println(Integer.toBinaryString(6297>>>5));   
6 System.out.println(Integer.toBinaryString(-6297>>>5));   
7 System.out.println(Integer.toBinaryString(6297<<5));   
8 System.out.println(Integer.toBinaryString(-6297<<5));  

 

运行结果:segmentfault

1100010011001post

11111111111111111110011101100111
11000100
11111111111111111111111100111011
11000100
111111111111111111100111011
110001001100100000
11111111111111001110110011100000测试

 

注:x<<y 至关于 x*2;x>>y至关于x/2y
    从计算速度上讲,移位运算要比算术运算快。
    若是x是负数,那么x>>>3没有什么算术意义,只有逻辑意义。spa

结果分析:code

位数:htm

00000000 00000000 00000000 00000000对象

6297
00000000 00000000 00011000 10011001
-6297
10000000 00000000 00011000 10011001   源码
11111111  11111111   11100111   01100110  反码 除符号位按位取反

11111111  11111111   11100111   01100111   补码 除符号位反码加1

6297>>5

00000000 00000000 00000000 11000100 <右移5位后>

-6297>>5

11111111 11111111 11100111 01100111 补码<十进制负数在计算机中二进制表示形式>

11111111 11111111 11111111  00111011 <右移5位后>

6297>>>5

00000000 00000000 00011000 10011001

00000000 00000000 00000000 11000100 <右移5位后>

-6297>>>5

11111111 11111111 11100111 01100111 补码<十进制负数在计算机中二进制表示形式>

0000011 11111111 111111111 00111011 <逻辑右移5位后> 存疑

6297<<5

00000000 00000000 00011000 10011001

00000000 00000011 00010011 00100000

-6297<<5

11111111  11111111   11100111   01100111   补码 除符号位反码加1<计算机中负数的存在形式>

11111111  11111100  11101100   11100000  <左移五位后>

=======================================================================

首先,移位操做符能操做的数只有int类型和long类型,这个是指左操做数的类型。对于int类型而言,int在Java中占4字节,一共32位,也就是说,对于一个在Java中的int数据,作32次移位,那么这个int数据就彻底变了,以左移为例,左移是补0,那么对于任意一个int类型数据,作32次移位,那么int数据变成32位全0的数据,Java不容许一次性移位左操做数的全部位,也就是右操做数不能大于32。因而回到上述的句子,其指的是右操做数的低5位,5位二进制所表明的最大值为2^5-1,为31,因此取右操做数的低5位,就是只看右操做数的二进制的低5位,其数值不会超过2^5次方,也就是int的32位。所以,移位操做符进行移位的实际次数,实际上是右操做数2的次数。

5位二进制所表明的最大值为2^5-1(注:2^5-1 -->32-1 = 31),为31
位数
0  0  0  0  0
每位的值
16 8  4  2  1
推测1:01111 -->15
推测2: 11111 -->31<无符号位>

对上面那段话的理解是:移位操做符操做的运算对象是二进制的“位”,int类型是32位也就是2的5次幂 !若是移32位以上,那么原来的数的信息会所有丢失,这样也就没有什么意义了!因此上面的“只有右侧的5个低位才会有用”说的是:移位操做符右端的那个数(化成二进制)的低5位才有用,即
X < <y;

是指y的低5位才有用,即不能大于32。 而对于long型也是一样的道理!

所以,若是对一个int 型,进行移位,X < <y; 当y小于32时,移位后的结果通常都在咱们的预料当中;而若是y大于32时,因为移位超出了int所能表示的范围,这时就先把y化成二进制数,而后取该二进制数右端的低5位,再把这5位化成十进制,此时的这个十进制就是要对X移动的位数。

 

例如:

int int a=140;
a << 34
System.out.println(Integer.toBinaryString(a << b));

上面那两个语句的执行过程是:先把a化成二进制数:10001100

执行语句 a << 34 对a左移32位时,先把 34化成二进制:100010,对该二进制数取右边5位,即00010,化成十进制数为2,因此其实是对a左移两位。如今,地球人都会知道上面程序的输出结果是:1000110000

//////////////////////////////////////////////////

移位运算符和按位运算符同样,同属于位运算符,所以移位运算符的位指的也是二进制位。它包括如下几种:
左移位(<<):将操做符左侧的操做数向左移动操做符右侧指定的位数 。移动的规则是在二进制的低位补0。

有符号右移位(>>):将操做符左侧的操做数向右移动操做符右侧指定的位数。移动的规则是,若是被操做数的符号为正,则在二进制的高位补0;若是被操做数的符号为负,则在二进制的高位补1。

无符号右移位(>>>):将操做符左侧的操做数向右移动操做符右侧指定的位数。移动的规则是,不管被操做数的符号是正是负,都在二进制位的高位补0。
注意,移位运算符不存在“无符号左移位(<<<)”一说。与按位运算符同样,移位运算符能够用于byte、short、int、long等整数类型,和字符串类型char,可是不能用于浮点数类型float、double;固然,在Java5.0及以上版本中,移位运算符还可用于byte、short、int、long、char对应的包装器类。咱们能够参照按位运算符的示例写一个测试程序来验证,这里就再也不举例了。
与按位运算符不一样的是,移位运算符不存在短路不短路的问题。
写到这里就不得不说起一个在面试题中常常被考到的题目:

请用最有效率的方法计算出2乘以8等于几?这里所谓的最有效率,实际上就是经过最少、最简单的运算得出想要的结果,而移位是计算机中至关基础的运算了,用它来实现准没错了。左移位“<<”把被操做数每向左移动一位,效果等同于将被操做数乘以2,而2*8=(2*2*2*2),就是把2向左移位3次。所以最有效率的计算2乘以8的方法就是“2<<3”。

最后,咱们再来考虑一种状况,当要移位的位数大于被操做数对应数据类型所能表示的最大位数时,结果会是怎样呢?好比,1<<35=?呢?
这里就涉及到移位运算的另一些规则:
byte、short、char在作移位运算以前,会被自动转换为int类型,而后再进行运算。 byte、short、int、char类型的数据通过移位运算后结果都为int型。 long通过移位运算后结果为long型。

在左移位(<<)运算时,若是要移位的位数大于被操做数对应数据类型所能表示的最大位数,那么先将要求移位数对该类型所能表示的最大位数求余后,再将被操做数移位所得余数对应的数值,效果不变。

好比1<<35=1<<(35%32)=1<<3=8。 对于有符号右移位(>>)运算和无符号右移位(>>>)运算,当要移位的位数大于被操做数对应数据类型所能表示的最大位数时,那么先将要求移位数对该类型所能表示的最大位数求余后,再将被操做数移位所得余数对应的数值,效果不变。。

好比100>>35=100>>(35%32)=100>>3=12。

另:

Java 的 Integer.toBinaryString 方法

public static String toBinaryString(int i)

    //以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。 
    //若是参数为负,该无符号整数值为参数加上 2^32;不然等于该参数。

        System.out.println(Integer.toBinaryString(-1)) ;
        System.out.println(Integer.toBinaryString(-2)) ;
        System.out.println(Integer.toBinaryString(1)) ;
输出:
        11111111111111111111111111111111
        11111111111111111111111111111110
        1

结论输出的是数字的二进制补码。为何说是以 二进制无符号整数形式 返回一个 整数类型的字符串,为何 若是参数为负数,就要加上 232 次方?

由于Java里的int是有符号的,在内存中没有正负之分,只有0/1,整数是用补码表示的

正数补码等于原码
负数的补码等于其绝对值的反码+1,正好等于自身+2^32(对于4字节的整型来讲)

-1 的补码 就是 绝对值1 的反码(按位取反) 11111111 11111111 11111111 11111110 再+1
等于 11111111 11111111 11111111 11111111

这样正好能把最高位为1的数字用来表示负数,而最高位为0的数字表示非负数

10000000 00000000 00000000 00000000 => -2147483648 11111111 11111111 11111111 11111111 => -1 00000000 00000000 00000000 00000000 => 0 00000000 00000000 00000000 00000001 => 1 01111111 11111111 11111111 11111111 => 2147483647 

所以负数+2^32以后的二进制串,就是该负数内存中准确的存储形式

相关文章
相关标签/搜索