背景
最近公司有来面试的,和他们沟通过后,看到公司的面试题上有这么一个题5|2的结果是什么
。然后被他们问到,我只知道是一个位运算题,具体的答案还真的不知道,作为技术人,求知的精神定然不能缺少;今天就来查缺补漏,对位运算进行一个回顾。
什么是位运算
位运算是对整数在内存中的二进制进行操作摘抄自百度百科
。就是对二进制进行操作,操作效率高,但是不易理解。
有哪些位运算
- a & b
与运算
- a | b
或运算
- a ^ b
异或运算
- ~a
非运算
- a << b
左移运算
- a >> b
右移运算
- a >>> b
无符号右移运算
运算的前提
因为运算是涉及到二进制,至少先要知道十进制和二进制的转换。
然后是要理解原码
、补码
、反码
概念,因为计算机存放的不是二进制的原码,存放的是二进制的补码。注意:运算之前都要将原码转换为补码
原码
原码即转换为二进制最初始的值
- 正数 5的原码(java int是32位):
00000000 00000000 00000000 00000101
- 负数 -5的原码(最左侧的1是符号位,1代表负)
10000000 00000000 00000000 00000101
反码
正数的反码和原码是一样的,负数的反码就是原码取反(符号位不参与转换)
- 正数 5的反码
00000000 00000000 00000000 00000101
- 负数 -5的反码
11111111 11111111 11111111 11111010
补码
计算机用存放补码的原因很简单,让加法可以实现加减的操作。
正数的补码和原码是一样的,负数的补码是原码取反加1(符号位不参与转换)
- 正数 5的补码:
00000000 00000000 00000000 00000101
- 负数 -5的补码
11111111 11111111 11111111 11111011
补码转原码
补码: 11111111 11111111 11111111 11111011
转为原码,有两种方法:
- 逆向推回去
先减一:11111111 11111111 11111111 11111010
取反:10000000 00000000 00000000 00000101
得出结果是 -5 - 按照原码转补码逻辑,再转一遍
先取反:10000000 00000000 00000000 00000100
再加一:10000000 00000000 00000000 00000100
得出结果是 -5
开始运算
& 与运算
与运算:只有两个操作数对应位同为1时,结果为1,其余全为0
负数运算
题目: 5 & -2
- 转换为原码
5 的原码:00000000 00000000 00000000 00000101
-2 的原码:10000000 00000000 00000000 00000010
- 转换为反码
5 的反码:00000000 00000000 00000000 00000101
-2的反码:11111111 11111111 11111111 11111101
- 转换为补码
5的补码:00000000 00000000 00000000 00000101
-2的补码:11111111 11111111 11111111 11111110
- 进行运算
00000000 00000000 00000000 00000101
11111111 11111111 11111111 11111110
00000000 00000000 00000000 00000100
(这是补码结果)
符号位是0,正数补码和原码一致,直接转换为十进制也就是 4
正数运算
题目 5 & 2
- 按照上述方法得出补码
5的补码:00000000 00000000 00000000 00000101
2的补码:00000000 00000000 00000000 00000010
- 进行运算
00000000 00000000 00000000 00000101
00000000 00000000 00000000 00000010
00000000 00000000 00000000 00000000
(这是补码结果)
将结果转换为十进制是 0
| 或运算
或运算:两个操作数对应位有一个为1,结果为1;都为0,结果是0
负数运算
题目 -5 | 2
- 还是老样子先算出补码
-5的补码:11111111 11111111 11111111 11111011
2的补码:00000000 00000000 00000000 00000010
- 进行运算
11111111 11111111 11111111 11111011
00000000 00000000 00000000 00000010
11111111 11111111 11111111 11111011
(这是补码结果)
需要注意,符号位是1,也就是负数的补码,负数的补码和原码不一样的,需要进行转换为原码。
先取反:10000000 00000000 00000000 00000100
再加1:10000000 00000000 00000000 00000101
正数运算
题目 5 | 2
按照之前的步骤,都转为补码,然后进行或运算;直接得出结果 7
~ 非运算
非运算,就是取反的过程,1取反为0,0取反为1
负数运算
题目 ~-5
- 转换为补码
11111111 11111111 11111111 11111011
- 求非
00000000 00000000 00000000 00000100
(这是补码结果)
结果转为十进制就是 4
正数运算
题目 ~5
按照原来的步骤,转补码,求非得出负数的补码,再将补码转为原码,得出结果为-6
^ 异或运算
两个同位的操作数,相同为0,相异为1
<< 左位移运算
a << b就是 a的补码向左移b个位数,低位的补零
正数运算
题目 5 << 2
- 将5转为补码
00000000 00000000 00000000 00000101
- 向左移2位,且低位补零
00000000 00000000 00000000 00010100
(补位结果)
得出结果为 20
负数运算
题目 -5 << 2
- 将-5转为补码
11111111 11111111 11111111 11111011
- 向左移2位,低位补零
11111111 11111111 11111111 11101100
(补位结果)
转换为原码10000000 00000000 00000000 00010100
得出结果为 -20
>> 右位移运算
和左移位运算相反,向右移,高位补零
>>> 无符号右位移运算
表示无符号右移,也叫逻辑右移;该数为正,则高位补0,而若该数为负数,则右移后高位同样补0
正数
正数的和 >> 的结果一样
负数
题目 -5 >>> 2
- -5 转为补码
11111111 11111111 11111111 11111011
- 进行右移2位,高位补零,不管符号位
00111111 11111111 11111111 11111110
(补码结果)
转为十进制为 1073741822
总结
之前总是畏惧位运算,因为涉及到了二进制;经过这两天的研究,发现没有那么难,主要是理解计算机存储的形式,然后按照计算机的逻辑进行推算,就可以得到结果。不过注意,计算要细心;最主要的一点是运算之前一定要转为补码
标签:11111111,java,运算,00000000,补码,负数,原码 From: https://blog.51cto.com/u_16321221/8009072