概念
1. 原码
即当前数字的二进制表现形式,其中第一位为符号位;
+1 原码为 0000 0001
-1 原码为 1000 0001
2.反码
正数的反码就是原码,负数的反码是符号位不变,其余位取反;
+1 反码为 0000 0001
-1 反码为 1111 1110
3. 补码
正数的补码就是原码,负数的补码是反码+1;
+1 补码为 0000 0001
-1 补码为 1111 1111
注意
对于正数,三种编码方式的结果都是相同的;而负数的原码、反码、补码各不相同;
计算机为什么使用补码?
使用原码时,人脑可以知道第一位是符号位,对于计算机来说,辨别符号位会使电路的设计变得十分复杂;而使用补码,不仅可以将符号位参与运算,而且计算机可以只有加法而没有减法,简化计算机运算的设计。关于计算机使用补码更详细介绍可参考http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html#!comments
位运算
运算符 | 名称 | 描述 | 样例 |
& | 按位与 | 如果相对应位都是1,则结果为1,否则为0 | 60=0011 1100 13=0000 1101 60&13=0000 1100=12 |
| | 按位或 | 如果相对应位都是0,则结果为0,否则为1 | 60|13=0011 1101=61 |
^ | 按位异或 | 如果相对应位值相同,则结果为0,否则为1 | 60^13=0011 0001=49 |
~ | 按位取反 | 翻转操作数的每一位,即0变成1,1变成0。(一元运算符) | ~60=1100 0011=-60 |
<< | 左移 | 左操作数按位左移右操作数指定的位数,右边补0,符号位也参与运算 | 60<<2=1100 0000=240 |
>> | 右移 | 左操作数按位右移右操作数指定的位数,左边补符号位,符号位也参与运算 | 60>>2=0000 1100=15 |
>>> | 逻辑右移 | 左操作数按位右移右操作数指定的位数,左边补0,符号位也参与运算 | 60>>2=0000 1100=15 |
注意
左移:将二进制每一位(包括符号位)左移,左边超出的位截掉,右边补0;
a为正数时,a<<n=a*2n ,a为负数不符合这个规则;
-2147483647 << 1 = 10000000 00000000 00000000 00000001 << 1
= 00000000 00000000 00000000 00000010 = 2
右移:将二进制每一位(包括符号位)右移,右边超出的位截掉,左边补符号位;负数还是负数,正数还是正数;
a!=-1时,a>>n=a/2n ;-1>>1=-1;
-2147483647 >> 1 = 10000000 00000000 00000000 00000001 >> 1
= 11000000 00000000 00000000 00000000 = -1073741824
逻辑右移:将二进制每一位(包括符号位)右移,右边超出的位截掉,左边0;结果都是一个正数;
-2147483647 >>> 1 = 10000000 00000000 00000000 00000001 >> 1
= 01000000 00000000 00000000 00000000 = 1073741824
小技巧
1. 获取整数n二进制的最后一位是0或1:n&1
33= 00000000000000000000000000100001
1= 00000000000000000000000000000001 33&1 = 1
32= 00000000000000000000000000100000
1= 00000000000000000000000000000001 32&1 = 0
2. 判断奇偶: n&1 或者n|0
3. 清零最低位的1 :n = n&(n-1)
4. 得到最低位的1:n&(-n)
应用
1. 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。(备注11)