作为一个程序员,始终要坚持一个信念,那就是
省屁吹灯,这也是一切的源头。
- CPU做加法运算最快。
- 尽量将减法运算转换成加法进行计算。
- 二进制表示数值时,最高是符号位,如果计算时要先判断符号再算,就复杂了。思路,让符号一起参与计算(像正常的加法一样)
原码
- 以
8位
二进制来表示一个数字
为例。最左边的第1位
作为符号位
,还剩下后7位
可以用来表示值
。
1.1. 正数
符号位为:0
:如: 1 的二进制为 00000001
1.2. 负数
符号位为:1
:如:-1 的二进制为 10000001 正数
的原码 = 反码 = 补码。所以我们在讨论反码, 补码
时主要是说负数
。- 之所以发明出
反码, 补码
就是为了让负数
的二进制运算,和正数
保持相同的运算规则(让符号位
参与计算并且将减法
转成加法
进行),最后还能得到我们想要的正确结果。
反码
- 正数:强调前面已经说过了
正数
的原码、反码、补码
都一样。 - 负数:
符号位
不变,其余
各个位取反
。
2.1. -1
原码:1000 0001
2.2. -1
补码:1111 1110 (放在256
大环中看此值为 254
离补数
还差1
) - 使用
反码
如愿让符号位
也参与计算了,但还有两个问题:
3.1. 我们得到的结果比真实结果少1
.
3.2. 存一个尴尬的负0
问题:1000 0000
补码
- 正数:再次强调前面已经说过了
正数
的原码、反码、补码
都一样。 - 负数:在
反码
基础上+1
。补上了反码运算少的1
,并使得正负0
的补码相同,解决了-0
问题。
-0
原码:1000 0000
-0
反码:1111 1111 (当作原码解析此值为 255
)
-0
补码:0000 0000 等于 +0
= 0000 0000 (符号位溢出
,又变回了正数) - 人为定义1000 0000 为
-128
,以至于我们看到的取值范围
负数会比正数多一位:[-128, 127]
原理
以时钟
为例,当前时针指向6
点,如果想将其调整为3
点,可以有两个方案:
- 顺时针调:
+9
即 6+9=3
。 - 逆时针调:
-3
即 6-3=3
。转为等价的加法:6+(12-3)
成功将减法-3
替换为+9
结果相同。因为它俩在一个12
的闭环当中,互为补数。
我们的补码
也是同理。 0000 0000 这8位
二进制数就是一个256
的大环。(最大值为255
再加1
到256
就是下一圈的0
了,就如同没有今夜的24点
,只有明天的0点
)
例:在256
的圆环中,向后-1
等于向前 +255
。
(+255
是 -1
以256
为模的补数
)
-1
原码:1000 0001
-1
反码:1111 1110 (放在256
大环中看此值为 254
离补数255
还差1
)
-1
补码:1111 1111。在反码
之上 +1
正好 +255
。
结论:减去
一个数,等于加上
这个数的补码
。因为补码
计算的便利性,所以计算机中实际存储的是补码
。
参考资料
张子秋的博客:原码, 反码, 补码 详解