一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0
, 负数为1
。
在介绍位运算符前先了解一下原码、反码和补码。
计算机中的有符号数有三种表示方法,即原码、反码和补码【实际上,计算机内参与计算的不是原码,而是补码】。三种表示方法均有符号位和数值位两部分,符号位都是用0表示正,1表示负,而数值位,三种表示方式各不相同。
表示方法 | 正数 | 负数 |
---|---|---|
原码 | 正常二进制数表示,即符号位0 | 正常二进制数表示,即符号位1 |
反码 | 与原码相同 | 符号位保持不变,数值位按位取反 |
补码 | 与原码相同 | 符号位保持不变,数值位按位取反后+1 |
计算机在使用原码进行加减乘除的运算时,需要根据数字符号位的正负从而执行不同规则的加法,如果采用单一的加法会导致结果出错,如下:
1 + 1 = [00000001]原 + [00000001]原 = [00000010]原 = 2 两正数结果正确
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2 存在负数结果错误
可以看到,如果用原码表示,让符号位也参与计算,显然对于减法来说,结果是不正确的,这也是为什么计算机不用原码表示一个负数。为了解决这个问题,出现了反码,如下:
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在0
这个特殊的数值上. 虽然人们理解上+0
和-0
是一样的, 但是0
带符号是没有任何意义的. 而且会有[0000 0000]
原和[1000 0000]
原两个编码表示0
。
于是补码的出现, 解决了0
的符号以及两个编码的问题:
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
这样0
用0000 0000]
表示, 而以前出现问题的-0
则不存在了,而且可以用[1000 0000]
表示-128
:
(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
综上所述:
反码:简化了计算机计算二进制加减的判断流程(将符号位直接参与运算不再会像原码那些可能存在错误结果的情况),降低了运算的复杂性,但是依旧存在零表示不唯一的问题。
补码:在反码的基础上,解决了零表示不唯一的问题,还增加了一个负数的一个表示范围(计算机字长为8位的原码或反码的表示范围为[-127, +127]
,而补码[-128, 127]
)。
运算符 | 描述 | 运算规则 |
---|---|---|
& | 按位与 | 两位都为1时,结果为1 |
| | 按位或 | 两位有至少一位为1时结果为1 |
~ | 按位非(取反) | 0变1,1变0 |
^ | 按位异或 | 两个位相同结果为1,相异为0(同1异0) |
<< | 左移 | 左移若干位,高位丢弃,低位补0 |
>> | 右移 | 右移若干位,正数:左补0右丢弃,负数:左补1,右丢弃 |