计算机怎么实现减法?

 计算机怎么实现减法?

我一直对计算机存储和处理信息的方式很好奇,初中的时候无意在知乎上看到了计算机存储整数的科普,了解到计算机内部是用二进制表示数据的,并且十进制的加法在计算机中的处理方式也是二进制加法,从那时起我就一直有一个疑问,计算机是怎么实现减法的呢?

在回答这个问题之前,我们先要更深入地了解信息在计算机内部的存储方式。

位和字节

我们把计算机的内存想象成一大片格子,每个格子都只能存放1、0中的一个数,这样一个单独的格子就叫“位”。多个位连在一起就组成字节,一般计算机上一个字节由八个位组成。

单个格子能存储的信息非常有限,只有0或1。然而当我们把多个格子,也就是位连在一起并且赋予这些位某种意义的时候,这些位就能表示大量信息。比如我们考虑八个连在一起的位,将这些位称作长度为8的位向量\underset{x}{\rightarrow} = [x_{7},x_{6},...,x_{0}],就可以表示数集{7,6,...0}的任何子集E。当i \epsilon E时,令x_{i} = 1,利用这种编码方式,就可以用位向量[0,0,0,1,0,1,0,0]表示数集{2,4}。

计算机中整数的编码

首先,我要请读者一定要把编码这个概念谨记于心,编码:指用代码表示各种信息,在计算机科学中,就是把信息转换成可以理解的二进制值!记住了编码,再来看接下来的内容。

整数由正整数、零和负整数组成。我们先来讨论零和正整数的编码方式。零和正整数,也就是无符号数的编码方式比较简单。我们还是考虑长度为8的位向量\underset{x}{\rightarrow} = [x_{7},x_{6},...,x_{0}],【位向量:你可以模糊地理解成一个二进制值】只需要这个位向量对应的二进制数直接转换成十进制,就可以得到对应的无符号数。下面给出这一编码方式的数学定义:

B2U_{w}(\vec{x})\doteq \sum_{i=0}^{w-1}x_{i}2^i

w代表位向量的长度。举个例子,长度为3的位向量\vec{x} = [1,0,1]所编码的无符号数是1\times 2^{2}+0\times 2^{1}+1\times 2^{0} = 4+1 = 5

 我们很容易可以考虑到,这种编码方式所能编码的整数范围是有限的,并且这个范围和长度w是正相关的。

长度为w的位向量\vec{x}所能编码的最大无符号数UMax_{w}= 2^{w}-1 

最小无符号数自然是0。

讲完了无符号数的编码方式,我们再来讨论有符号数,即正整数、零和负整数组成的数集的编码方式。

计算机发展历史中,一共出现过三种把位向量编码为负整数的编码方式,分别为原码、反码和补码,目前几乎所有计算机底层都是使用补码编码有符号数。大部分人第一次接触到原码、反码补码时都会一头雾水,不明所以,至少我身边的同学是这样。私以为,原因无他,就是国内对这三个名词翻译太离谱了,就算只写出Sign-Magnitude,Ones'Complement,Two's complement,直接不翻译,相信正常人查下字典都能把这三个术语的意思弄明白个大概。Sign符号,Magnitude大小,那自然就是符号值嘛!后面两个可能有点奇怪,但是随后等我介绍完反码和补码的定义后,你自会发现,英文名的命名逻辑比中文名的正常清晰多了。

原码

扯远了,下面先来介绍最早出现的原码。我们很容易可以想到一种用位向量编码有符号数的方式,即以最高位,即x_{w-1}【看不懂这个的回过头去看位向量的定义】表示正负,1为负,0为正,剩下的w-1位正常编码。乍一看这种编码方式很方便,好像没有问题啊,但是其实问题多了去了啊! 

B2S_{w}(\vec{x})\doteq (-1)^{x_{w-1}}\cdot \left ( \sum_{i}^{w-2}x_{i}2^{i} \right )[1,1,0]

(原码的数学定义) 

我们先回过头来想想,把位向量编码为整数值要解决什么问题?

1.提供一种转换方式,让计算机可以存储整数数据。

2.这种转换方式,要能让计算机以一种统一、逻辑自洽的方式处理整数数据,通俗地讲,就是计算机在处理整数运算之类的数据处理时,要符合逻辑,不能乱来。

那么原码这种编码方式有什么错误呢?首先,以长度为4位的位向量为例,-1这个数按照我们刚刚的编码方式被解释为1001,1被解释为0001,-1+1理应等于0,但是计算机只能执行二进制加法啊,所以-1+1会先被以原码编码转换为二进制数,再执行运算,最后1001+0001的结果是1010,这显然是错误的。

除此之外,原码奇特的编码方式还会带来一个问题,即会出现+0和-0,10代表-0,00代表+0,但在数学中,+0、-0显然是不存在的。为了修补原码带来的这些问题,计算机内部还要添加额外的物理结果,或者执行额外的运算,我们当然不想出现这种结果,因此,反码登上了历史舞台。

反码

我们仍以长度为4位的位向量为例。怎么解决原码中出现的4+-4不等于0的问题呢?考虑下面一个等式: [1111]-x + x =[1111] 

是不是隐隐约约地觉得,这个等式和我们要实现的-x+x = 0还有点儿像?

如果有一种编码方式把[1111]-x编码为-x,那么自然,[1111]就能会被编码为0,上述等式就变成了-x+x = 0

反码,就是这样的一种编码方式。现在我们知道了反码的由来,就可以回答刚刚留下来的那个问题啦,为什么反码要叫Ones' Complement? 这个命名是基于,在反码编码中,-x的二进制是以[1111....]-x,即2的w-1次方-1 -x,表示的,所以是One,而且后面还有s(注意,补码的英文名字是Two's Complement,s不在Two的后面),complement补,是不是很形象?

反码的数学定义:

B2O_{w}\left ( \vec{x} \right )\doteq -x_{w-1}(2^{w-1}-1)+\sum_{i=0}^{w-2}x_{i}2^{i}

 举个例子,长度为3的位向量 [1,1,0]以反码编码的有符号数是

-1(2^{2}-1)+1\times 2^{1} + 0\times 2^{0} = -1

再举个例子,帮助大家理解反码编码-x的定义,x=4,以长度为5的位向量编码,那么-4的二进制表示应该是[11111]-4,也就是31-4,即27,再转换为二进制,就是11011!

再验证一下反码编码的正确性,-4+4,被转换为11011和00100,在计算机内部执行加法,11011+00100 = 11111 ,而11111在反码编码中被解释为0!

简直太神奇了!

但是,反码仍是存在缺陷的。在反码中,[1111...]和[0000....]被同时编码为0,这个问题仍没有解决,反码仍然是无法逻辑自洽的。

补码

最后,补码的出现解决了遗留下来的问题。在介绍补码的概念之前,计算机中表示数据所用的位数是固定的,如果计算机表示数据所用的位数是4位,超过4位的整数编码就会被强制转换为4位。利用这一性质,仍以4位为例,我们可以得到一个式子:

[1111]+[0001] -x + x=0

像在反码编码中我们做的一样,我们把-x的补码编码表示为[1111]+[0001]-x的二进制值,x表示为x的二进制值:

得到如下的数学定义:
B2T_{w}\left ( \vec{x} \right )\doteq -x_{w-1}(2^{w-1})+\sum_{i=0}^{w-2}x_{i}2^{i} 补码和反码的唯一区别就是,-x w-1的乘数是2的w-1次方,而不是2的w-1次方-1。

现在我们也可以解答上面留下来的问题了,为什么补码的英文名是Two's complement?这实际上是基于:-x的二进制是以[1111....]+[000..1]-x,即2的w次方减去x,表示的

补码充分地利用了计算机存储信息时会【溢出】的特性,提供了一个逻辑自洽的体系供计算机执行整数的存储和处理。

讲了那么多,相信你已经知道计算机是怎么执行减法的了。把负数用补码编码,直接化为加法运算。

至于为什么不再在计算机内部设置一个和加法器类似的减法器呢?当然是因为麻烦呗!给数据编码是无法避免的计算消耗,如果在编码过程中就能把减法解决,那么为什么要再花费更多的资源去添加减法器呢?
 

写在最后

大一新生第一次写技术类博客,如有疏漏,烦请指出~~~~~

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值