大家好,我是程序员牛肉。
最近在学《计算机组成原理》,在学习计算机数据的表示和运算这一章节的时候,有一个知识点吸引了我的注意力:
计算机对减法是通过加法的路径来实现的。
有点绕口令了。而这篇文件就来探寻一下“计算机对减法是通过加法的路径来实现”的 底层原理 。
在进入正题之前,我们要在这里先介绍一些前置知识。
计算机的最小存储单元是“字节”,一个字节等于八个bit,一个bit位可以表示两种信息(0 或 1)。
因此八个bit位就可以表示28个不同的信息,也就是256种不同的状态,所以一个字节的大小如果表示正数的话,可以表示0-255的数字。
而数字是有正有负的,计算机并没有办法存储正负符号。因此我们制定了一个规范,约定以一个字节的头部bit位作为符号位。
“1”表示当前数字是负数,“0”表示当前数字是负数。
而这种用最高位作为符号位,其余空间存储数字的方式,就叫做源码。除了源码之外,我们还有“反码”和“补码”。
正数的反码就是本身,负数的反码是将一个二进制数除过符号位之外按位取反的结果。
正数的补码也是自己本身,负数的补码是自己的反码+1。
其实很轻易就可以看出来:反码和补码都是针对于负数而言的。
而计算机在存储数据的时候,都是存储数据的补码。主要就是为了让计算机的加法器能同时实现减法和加法两种运算。
当我们尝试 1 - 1 的时候,可以用1+(-1)来表示。我们来看看分别采用源码,补码,反码的结果(只有八个bit,超出的话会溢出)。
我们可以看出当使用了补码之后,我们成功的实现了把一个减法操作变为了加法。
我们来看看这个底层原理到底是为什么。
解析
IN JULY
补码机制
我们之前说过一个字节的大小存储二进制数字的话,最多就存储0-255。他们的二进制分别是从0000 0000 到 1111 1111。当 255再加1到256的时候,实际上八个bit位是无法正常表示256的 ,此时就回到了0。
由此我们可以看到,在一个字节的大小范围内,实际上是存在溢出循环的。当1111 1111再加1之后就会溢出,八位bit位并没有办法表示 1000 0000 0 这九位数字,只能保存0000 0000 。也就是从 0 到 255不停的进行循环。
像这种数字不断循环的案例,其实我们的日常生活中就很常见:钟表
时钟也是不停的从0-12循环,和我们刚才说的一个字节存储数据的形式是完全一样的。
那现在我们假设这样一种情况:现在是三点,我们要从下午15点调回上午12点。请问有几种方法?
我们要么逆时针调三个小时,要么顺时针调八个小时。
其实可以用算式表示为:
在这个式子中,我们要引入两个概念
模:能表示最多的离散数字的格式,例如在这个钟表里的模就是12。
同余:无论是-3还是9,这两个数字对12进行取余的结果都是12。因此说这两个数字同余。
在同一个模里,同余的数在加法中是等效的。
这其实是数论里的知识,感兴趣的同学可以再深入了解一下。
让我们把钟表这种模式映射到我们一个字节中,就好比有一个钟表,他的刻度是从0-255。
那么他的模就是 256 ,两个互余的数字可以通过公式进行转换。
在二进制的 255 -3 式子中,-3 和 253 互余。我们就可以认为:
通过这种形式,我们就把一个加法转换成了一个减法。
而当我们回顾前面的补码概念,可以得到-3的补码是11111101,也就是253。
因此我们可以知道:
补码的本质就是在寻找在一个模中,与当前负数同余的另外一个正数。
相信通过我的介绍,大家已经大致了解“计算机是如何通过加法实现的减法”,希望这篇文章能够帮到你。