原码,反码,补码
计算机底层是以二进制表示的,计算机可以用原码
,反码
, 补码
这三种编码方式表示一个数。对于正数
,三种编码方式都相同。对于负数,三种编码方式对应的二进制是完全不同的。
原码是我们可以直接识别的,为什么还要用反码和补码呢?
对于计算机,加减乘除已经是最基础的运算。要设计的尽量简单,计算机辨别符号位显然会让计算机的基础电路设计变得十分复杂
,于是人们想出了将符号位也参与运算的方法
。
根据运算法则减去一个正数等于加上一个负数,即:1-1=1+(-1)=0;所以机器可以只有加法而没有减法
,这样计算机运算的设计就更简单了。但是,如果用原码计算。比如1 - 1 = 1 + (-1) =[0000 0001]原+[1000 0001]原=[1000 0010]原 = -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]补+[1111 1111]补=[0000 0000]补=[0000 0000]原。
左移运算符 <<
12345 二进制表达:
0000 0000 0000 0000 0011 0000 0011 1001
左移动一位 << 1:
000 0000 0000 0000 0011 0000 0011 10010
结果就变为了24690,刚好是12345的二倍。
左移动19位 << 18:
11 0000 0011 1001 0000 0000 0000 0000 00
结果变为-1058799616
如果左移32位,那表示的还是数字本身。如果左移数n大于32位,左移位数 = n%32。
右移运算符 >>
右移过程中,正数左边补0,服务左边补1
。
12345 二进制表达:
0000 0000 0000 0000 0011 0000 0011 1001
右移一位 >> 1:
00000 0000 0000 0000 0011 0000 0011 100
结果就变为了6172 ,和int 类型的数据12345除以2取整所得的值一样。
-12345二进制表达:
原码:1000 0000 0000 0000 0011 0000 0011 1001
反码:1111 1111 1111 1111 1100 1111 1100 0110
补码:1111 1111 1111 1111 1100 1111 1100 0111
右移一位 >> 1:
补码:1111 1111 1111 1111 1110 0111 1110 0011
补码的补码 = 原码
反码:1000 0000 0000 0000 0001 1000 0001 1100
原码:1000 0000 0000 0000 0001 1000 0001 1101
结果就变为了-6173
无符号右移运算符
<<< 与 >>> 与左移,右移一样。不过无符号右移运算符在右移的时候是补0的
,而右移运算符是补符号位的
。