此文是基于
阮一峰大神的文章-关于2的补码
的学习总结,便于加深印象和回顾,若想看原文,请走刚才的传送门~
负数在计算机中如何表示呢?
在计算机内部采用2的补码(Two’s Complement)表示负数。
什么是2的补码?
它是一种数值的转换方法,要分二步完成:
-
第一步,每一个二进制位都取反值,
0
变成
1
,
1
变成
0
。比如:
00001000
取反为
11110111
; -
第二步,将上一步的得到的值
+1
。即:11110111 + 1 = 11111000;
所以,
11111000
为
00001000
的补码,也就是说
-8
在计算机中用
11111000
表示;
为什么要用补码来表示负数呢?
对于计算机,加减乘除是最基本的运算,要尽量设计的很简单;
- 运算法则减去一个数等于是加上这个数的负数;
- 计算机的基础电路只有加法,使得设计更加简单;
由于对于二进制的编码有三种方式:
原码
、
反码
和
补码
;
-
使用原码进行
正数 + 负数
的类减法所得的结果并不正确; -
使用反码进行计算时,结果的真值部分是正确的,但是会有一个特殊的值:
0
。由于0是具有符号位是没有任何意义的,并且会有
1000 0000
和
0000 0000
两个编码表示0; -
使用补码进行计算可以完美解决真值、符号位和0的问题,同时由于
(-1) - (-127) = -128
,补码会以
1000 0000
表示 -128,即还能够表示一个最低数。 -
原码和反码表示的范围为
[ -127, 127 ]
,而补码可以表示
[ -128, 127 ]
;
2的补码的本质:
负数可以换成是
0 - 正数
得到的,因此 对于 -8 可以看做是
0 - (+8)
得到的;
那么对于二进制的来说即如下形式:
0 0 0 0 0 0 0 0
- 0 0 0 0 1 0 0 0
--------------------------
1 1 1 1 1 0 0 0
因为 被减数
0000 0000
小于减数
0000 1000
,因此需要向上一位借1,因此实质上被减数是
1 0000 0000
;
1 0 0 0 0 0 0 0 0
- 0 0 0 0 1 0 0 0
--------------------------
1 1 1 1 1 0 0 0
进一步观察可以发现,
1 0000 0000
是由
1111 1111 + 0000 0001
所得,因此:
1 1 1 1 1 1 1 1
- 0 0 0 0 1 0 0 0
--------------------------
1 1 1 1 0 1 1 1
+ 0 0 0 0 0 0 0 1
--------------------------
1 1 1 1 1 0 0 0
2的补码的转换步骤就是这么来的;
为什么正数加法适用于2的补码?
事实上,我们要证明的是
X - Y
或
X + (-Y)
可以用
X + Y
的2的补码完成;
根据上面的所说的,Y的2的补码可以用
1111 1111 - Y + 1
来表示;
即:
X + (-Y) => X + ( 1111 1111 - Y + 1 ) = Z
;
基于以上算式,分为
两种
情况讨论:
- 第一种,X < Y,Z 应该为负数,那么对 Z 采用2的补码的逆运算求出正数值然后在加一个负号即可得到
Z = -[ 1111 1111 - ( Z - 1 ) ]
Z = -[ 1111 1111 - ( X + ( 1111 1111 - Y + 1 ) ) + 1 ] = X - Y;
-
第二种,X > Y,那么 Z 肯定大于 1111 1111,但是我们假定这是8位机,最高位第9位溢出被舍弃,相当于减去
1 0000 0000
,因此:
Z = Z - 1 0000 0000 = X + ( 1111 1111 - Y + 1 ) - 1 0000 0000 = X - Y
另外,还有一种方法证明:
Z = X - Y = X + 1111 1111 - Y + 1 = X - Y + 1 0000 0000,
由于是8位机,是不可能出现第9位的(被舍去),即
Z = X - Y + 0000 0000 = X - Y;