计算机中整数为什么以补码的形式存储

引子

你知道计算机中以什么形式存储整数吗?是符号位加值位吗?值位是按照正常的二进制方式存储的吗?
如果后两个问题你都回答是,那就意味着当用三位二进制进行存储、且符号位为0表示正数符号位为1表示负数时,1会存储为001,-1会存储为101。可惜事实不是这样,计算机中是以补码的形式而不是用刚刚那种很自然的形式存储整数,补码虽然也是用符号位加值位来表示,但表示的规则不太一样:1会存成001,-1会存成111。
计算机中为什么要采用这样的补码的形式呢?对于人脑,可以知道第一位是符号位,在运算的时候会根据符号位,选择对值位区域的加减。但是对于计算机,加减乘除已经是最基础的运算,要设计的尽量简单,计算机识别"符号位"显然会让计算机的基础电路设计的十分复杂,为了简化计算机基本运算电路,于是人们想出了让符号位也参与运算的方法。我们知道,根据运算法则减去一个正数等于加上一个负数,即1-1=1+(-1)=0,所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了。

探索过程

原码

计算十进制的表达式:1-1=0

1 - 1 = 
1 + (-1) = 
[00000001]原 + [10000001]原 = [10000010]原 = -2

如果用原码表示,让符号位也参与计算,显然对于减法来说结果是不正缺的。这也就是为何计算机内部不使用原码表示一个数。

反码

为了解决原码做减法的问题,出现了反码:

正数的反码是其本身  
[+1] = [00000001]原 = [00000001]反
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反
[-1] = [10000001]原 = [11111110]反

计算十进制的表达式:1-1=0

1 - 1 =
1 + (-1) = 
[0000 0001]原 + [1000 0001]原=
[0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

发现用反码计算减法,结果值位的部分是正确的。唯一的问题出现在"0"这个特殊的数字上,虽然人们理解上+0和-0是一个意思的,但是带符号的0是有[0000 0000]原和[1000 0000]原两个编码表示0.

补码

补码的出现解决了0的符号及两个编码的问题

怎么计算补码:正数的补码是它本身;负数的补码是它的反码加一。

1-1 = 
1 + (-1) = 
[0000 0001]原 + [1000 0001]原 = 
[0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了。而且可以用[1000 0000]表示-128:

(-1) + (-127) = 
[1000 0001]原 + [1111 1111]原 = 
[1111 1111]补 + [1000 0001]补 = [1000 0000]补

-1-127的结果应该是-128,在用补码运算的结果中,[10000000]补就是-128。但是注意因为实际上是使用以前的-0的补码来表示-128,所以-128并没有原码和反码表示。(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)。
使用补码, 不仅仅修复了0的符号以及存在两个编码的问题,而且还能够多表示一个最低数。这就是为什么8位二进制,使用原码或反码表示的范围为[-127,+127],而使用补码表示的范围为[-128, 127]。
因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-2^31, 2^31-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

完善补码

问题

通过转换成补码,减一个数确实变成加一个数了,看似很不错,但却有一个明显的问题,那就是数本身的符号丢失了。
比如3位二进,正常表示0~7,使用补码法它能代替-8~-1的运算,但它不能真正表示-8~-1,因为你不知道它到底是正数还是负数。
我们把负数转换成了一种在运算中更让计算机喜欢的形式,但它却丢失了自己本身作为数的信息。

扫描二维码关注公众号,回复: 3735772 查看本文章

如何完善

  • 在保持补码特性的前提下(也就是减一个数还是照样变成加一个数)
  • 增加正负的表示(能真正表示-8~-1了,只用看符号位是0还是1)
  • 还能让运算时不用另外区分符号位,直接把符号位当成值位进行运算,而结果的正负号自然会符合这个正负表示法(也就是符号位的进位和值位的进位都会自然地合理)

具体做法是:在左侧高位增加一个符号位,这个符号位连同前面我们推演出的伪补码 一同构成真正完善的补码。
实现的效果:通过读取符号位能得知数的正负,同时符号位在加法运算中跟值位一样参与运算、进位、退位。

总结

  1. 使用补码的目的:简化计算机基本运算电路,使加减法都只需要用加法电路实现,用加法替代减法。
  2. 补码为什么能达到这个目的:n位二进制可以构成一个可溢出计数系统,在这样的系统中,把计数系统容量作为模,所有对此模同余的数在此计数系统中都会有同样的表示,而且运算等价。而补码就是负数的最小正同余数,所以加一个负数和减一个正数都可以用加一个补码来表示。

猜你喜欢

转载自www.cnblogs.com/ninety/p/9856404.html
今日推荐