根本原因:计算机中使用原码计算会出错是因为将机器码当作二进制进行了计算,即想当然地认为:
a
+
b
=
[
a
]
原
+
[
b
]
原
a + b = [a]_原 + [b]_原
a+b=[a]原+[b]原
但是,如果机器中用原码表示数字,则其规律不符合二进制的计算规则。
简单解释一下,以8位二进制为例:
如果使用原码,如下表
机器码 | 代表的真值 | |
---|---|---|
正数 | 0000 0000 ~ 0111 1111 | +0 ~ 127 |
负数 | 1000 0000 ~ 1111 1111 | -0 ~ -127 |
表示范围为 -127 ~ 127,且有两个零值。
如果使用补码,如下表
机器码 | 代表的真值 | |
---|---|---|
正数 | 0000 0000 ~ 0111 1111 | +0 ~ 127 |
负数 | 1000 0000 ~ 1111 1111 | -128 ~ -1 |
表示范围为 -128 ~ 127,不存在两个零值的问题。
8位二进制的计数规律可以表示为如下循环:
按照箭头方向,由二进制加法可以互相转换,也就是说,要将机器码按照二进制数计算规则进行计算,其表示方法必须符合这个循环。
我们回过头来看原码和补码的表示:
补码:真值的计数方向与二进制计数方向一致
原码:真值的计数方向与二进制计数方向不一致
有了正确的计数循环之后,就可以使用机器码进行计算了,此外,这个循环还可以解释为什么有:
[
a
]
补
−
[
b
]
补
=
[
a
]
补
+
[
−
b
]
补
[a]_补 - [b]_补 = [a]_补 + [-b]_补
[a]补−[b]补=[a]补+[−b]补
将循环中的箭头方向理解成加减(图中顺时针为加,逆时针则为减),所加/减的数即为该数的补码在循环中按顺时针与
[
0
]
补
[0]_补
[0]补的距离。例如:
0
−
1
=
[
0
]
补
−
[
1
]
补
=
[
0
]
补
+
[
−
1
]
补
0 - 1 =[0]_补 - [1]_补 = [0]_补 + [-1]_补
0−1=[0]补−[1]补=[0]补+[−1]补
如下图所示,减1是逆时针1到0的“距离”,加(-1)是顺时针(-1)到0的“距离”,所得结果相同,所以上式成立。
以上纯属个人理解,如有错误,欢迎指正。