2023-08-30 16:56:00
我们都知道在计算机存储的时候,有符号的数都会用最高位作为符号位。
参考:什么是原码、反码和补码
原码
就是正常的二进制数,把最高位改成符号位(0为正数,1为负数)。
正数计算不会有问题:
5+2:
0 0 0 0 0 1 0 1
+ 0 0 1 0
-----------------
0 0 0 0 0 1 1 1
=7
反码
正数的反码就是原码,负数的反码是把原码中除符号位以外的所有位(数值位)取反。
为什么要引入反码呢?因为计算机中直接用原码加减只能解决正数加减,而带负数加减如果用原码就会出现很大的错误,如:
-56-1:原码
1 0 1 1 1 0 0 0
- 1
-----------------
1 0 1 1 0 1 1 1
=-55???
那如果我们用反码运算:
-56-1:反码
1 1 0 0 0 1 1 1
- 1
-----------------
1 1 0 0 0 1 1 0
=-57
没有任何问题。
补码
正数的补码是原码,负数的补码是反码加 1。
为什么要搞出一个奇奇怪怪的补码?
因为用反码做负数跨 0 运输也会错。
如:-3+5:反码
1 1 1 1 1 1 0 0
+ 0 1 0 1
-----------------
0 0 0 0 0 0 0 1
=1??
用补码:
1 1 1 1 1 1 0 1
+ 0 1 0 1
-----------------
0 0 0 0 0 0 1 0
正确。
不仅如此,如果用反码,0的表示就有了歧义,+0反码00000000
,-0反码11111111
,而且还浪费一个位置,但是用补码则不然。这也是为什么 int
的范围是 \([-2147483648,2147483647]\),负数可以多表示一个,而 \(-2147483648\) 在 4 字节整型中并没有原码和反码,只有补码。
补码变原码:
- 先减1再取反
- 先取反再加1
个人认为第二个好记。
注:
进行位运算时用的都是补码,所以 OIer 们判断是不是 \(-1\) 常用 ~p
,如果是 -1 的话,结果就是0,也是因为 -1 的补码是全 1。