无论你是使用的最低端的51单片机还是最高端i9处理器,在这个处理器中只有加法运算电路没有减法运算电路,若你过有一些计算机基础,大概应该知道这是通过补码实现的。但处理器是如何将通过补码加法实现减法的呢?
1. 补码又是如何实现将加法运算转换成加法的呢?
首先我们先看加法和减法的本质到底是什么,从网络上能搜索到很多关于加减法本质的理解,自认为一个比较好的解释是从数轴的角度去理解加减法的本质:
- 加法的本质是将一个数向右移动,如a+b,是将数a向右移动b个单位
- 减法的本质是将一个数向左移动,如a-b,是将数a向左移动b个单位
在数学上整数的数量是无限的,而在处理器中为了平衡效率和性能,对整数的表示一般为有限个数,如uint8(用8个bit位去表示一个整数)最大能表示256个数、uint16最能表示65536个数、uint32可表示4294967296(约42亿)个数,当使用有限长度空间去表示整数后将会产生一个在数学上不会出现的现象---溢出(溢出的高位被抛弃),如uint8最大能表示255,这时若向其赋值256,这个数将产生溢出,溢出后会变成0,同理向其赋值257后会变成1.
基于处理器存在溢出规律的特性,那么一定存在一个数b使得
在数学上这个b只能是0,而在处理器中除了是0外还可以是最大能表示数的个数,如uint8中可以是256以及256的整数倍,同理处理器中减法也存在类似规律
基于以上规律,对于减法
可以等价于:
按上述加减法的本质可以这样理解:对向左移动个单位与对向右移动个单位后将是同一个数。这里就将减法转换成了中的加法,而其中就可以就可以认为是是补码,这里的的不是通过减法实行,而是我们经常听说的“按位取反再加一”计算方法得到。
2. 为什么“按位取反再加一”可以计算-y的补码?
对于任意一个原码加上其反码可以得到该范围的最大数,如下图所示:
范围内能够表示数量可等于范围内最大数加一,即:
上面的数的反码+1即为数的补码。这个没有使用减法而是通过“按位取反加一”就能计算得到数的补码。
3. 在补码为什么符号位可以直接参与加法计算?
为了区分正数与负数,在原码、反码以及补码中都使用了二进制的最高位来标识正负数,正数的最高位使用'0',负数的最高位使用'1'。所有的情况,共有如下三种情况:
其中c=a+b中的符号位都使用'0'表示,符号位相加并不存在进位溢出问题,这个符号位及时参加了整个运算也不影响结果。
在中,符号位都是'1',两个二进制位'1'相加一定会产生进位溢出,按理说最高位符号位由于进位溢出会从'1'变成'0',即从负数变成正数,但实际上运算后仍然为‘1’,那么后面的补码一定需要产生溢出进位才会将符号位再次变成‘1’,那后面的数的加法一定会产生进位溢出吗?原理如下:
在中,若满足,那么一定会使产生溢出使符号位最终变成‘1’,而条件是我们使用者进行保证的,若发现可能存在溢出那就需要使用一个更多位数的二进制位来表示。
在中,若结果为非负符号位为‘0’,若结果为负符号位为‘1’,原理如下:
在中,若满足一会产生进位溢出使再次使符号变成‘0’,若满足并不会进位溢出使符号维持为‘1’.