首先区分两个概念:真值与机器码
- 真值:一般书写的数
- 机器码:机器中表示的数
为了解决在计算机内部数的正、负符号和小数点运算问题,而产生了把符号位和数值位一起编码来表示相应的数的表示方法,如原码,反码,补码,移码
1.原码
- 表示方法:
符号位 + 二进制数的绝对值
- 符号位:0为正,1为负,有+0与-0之分
正数:0+二进制数
负数:1+二进制数
- 特点:表示简单,易于同真值之间进行转换,实现乘除运算规则简单。但进行减运算十分麻烦
- 例子:3的二进制数是11,则+3的原码是011,-3的原码是111
- 使用原码做减法(
1−1=0
1
−
1
=
0
)
1−1=1+(−1)=[00000001]原+[10000001]原=[10000010]原=−2 1 − 1 = 1 + ( − 1 ) = [ 00000001 ] 原 + [ 10000001 ] 原 = [ 10000010 ] 原 = − 2
结果错误
2.反码
- 表示方法:
正数的表示与原、补码相同. 负数的反码符号位为1,数值位是将原码的数值按位取反,就得到该数的反码表示。
- 符号位:0为正,1为负,有+0与-0之分
正数:0+二进制数
负数:1+二进制数按位取反
- 特点:为求补码提供便利
- 例子:3的二进制数是11,则+3的反码是011,-3的反码是100
- 使用反码做减法(
1−1=0
1
−
1
=
0
)
1−1=1+(−1)=[00000001]原+[10000001]原=[00000001]反+[11111110]反=[11111111]反=[10000000]原=−0 1 − 1 = 1 + ( − 1 ) = [ 0000 0001 ] 原 + [ 1000 0001 ] 原 = [ 0000 0001 ] 反 + [ 1111 1110 ] 反 = [ 1111 1111 ] 反 = [ 1000 0000 ] 原 = − 0
结果正确,但出现了-0,这里的-0和+0是没有区别的,所以在这里让0带符号是没有意义的(数学上有时候需要带符号的0,但这里确实不需要,而且会使得对于同一个数有两种编码方式)
3.补码
- 表示方法:
正数的补码符号位为0 ,尾数与原码相同. 负数的补码符号位为1,数值位是将原码的数值按位取反,再在末位加1
- 符号位:0为正,1为负,无+0与-0之分
正数:0+二进制数
负数:1+(二进制数按位取反,末位+1)
- 特点:将减法转化为加法
- 例子:3的二进制数是11,则+3的补码是011,-3的补码是101
- 使用补码做减法
-
1−1=0
1
−
1
=
0
1−1=1+(−1)=[00000001]原+[10000001]原=[00000001]补+[11111111]补=[00000000]补=[00000000]原 1 − 1 = 1 + ( − 1 ) = [ 0000 0001 ] 原 + [ 1000 0001 ] 原 = [ 0000 0001 ] 补 + [ 1111 1111 ] 补 = [ 0000 0000 ] 补 = [ 0000 0000 ] 原
结果正确,且没有出现-0,这里是正负相加的结果,那如果是通过正正相加或者负负相加得到 [10000000]补 [ 1000 0000 ] 补 ,又意味着什么呢? - 正正相加:(
27−1)+1=128
2
7
−
1
)
+
1
=
128
正溢
(27−1)+1==[01111111]原+[00000001]原=[01111111]补+[00000001]补=[10000000]补=[10000000]原 ( 2 7 − 1 ) + 1 == [ 0111 1111 ] 原 + [ 0000 0001 ] 原 = [ 0111 1111 ] 补 + [ 0000 0001 ] 补 = [ 1000 0000 ] 补 = [ 1000 0000 ] 原
这里可以看到,用补码时, [10000000]原 [ 1000 0000 ] 原 表示上溢的结果 - 负负相加:
−26+(−26)=−128
−
2
6
+
(
−
2
6
)
=
−
128
负溢
−26+(−26)==[11000000]原+[11000000]原=[11000000]补+[11000000]补=[10000000]补=[10000000]原 − 2 6 + ( − 2 6 ) == [ 11000000 ] 原 + [ 11000000 ] 原 = [ 11000000 ] 补 + [ 11000000 ] 补 = [ 1000 0000 ] 补 = [ 1000 0000 ] 原
这里可以看到,用补码时, [10000000]原 [ 1000 0000 ] 原 也可以表示下溢的结果
-
1−1=0
1
−
1
=
0
在定点整数机器中,数的表示范围为
|x|<(2n−1)
|
x
|
<
(
2
n
−
1
)
,但n位二进制补码数的表示范围是
−2n−1
−
2
n
−
1
到
2n−1−1
2
n
−
1
−
1
,
其中用
[10000000]原
[
1000
0000
]
原
来表示
−2n−1
−
2
n
−
1
,这样不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].
但是,同时要注意,用补码表示的
−2n−1
−
2
n
−
1
是没有对应的反码和原码的,因为实际上是使用以前的-0的补码来表示-128
4.移码
- 表示方法:
移码和补码尾数相同,符号位相反
- 符号位:1为正,0为负(注意,移码的符号表示与其他三种都不一样)
正数:1+二进制数
负数:0+(二进制数按位取反,末位+1)
- 特点:通常用于表示浮点数的阶码
- 例子:3的二进制数是11,则+3的移码是111,-3的移码是001
比较
表示方法 | 正数 | 负数 | +1011111 | -1011111 |
---|---|---|---|---|
原码 | 0+二进制数 | 1+二进制数 | 01011111 | 11011111 |
反码 | 0+二进制数 | 1+二进制数按位取反 | 01011111 | 10100000 |
补码 | 0+二进制数 | 1+(二进制数按位取反,末位+1) | 01011111 | 10100001 |
移码 | 1+二进制数 | 0+(二进制数按位取反,末位+1) | 11011111 | 00100001 |