什么是符号位如何让计算机理解哪些是正数 为什么手机要补码呢( 二 )


假设我们使用Java中的32位整型来表示2 , 它的十进制是000…010 。最低的两位是10 , 前面的高位都是0 。如果我们使用-2的原码 , 也就是100…010 , 然后我们把3的二进制原码000…011和-2的二进制原码100…010相加 , 会得到100…0101 。具体计算你可以看我画的这幅图 。
二进制编码上的加减法和十进制类似 , 只不过 , 在加法中 , 十进制是满10才进一位 , 二进制加法中只要满2就进位;同样 , 在减法中 , 二进制借位后相当于2而不是10 。
相加后的结果是二进制100…0101 , 它的最高位是1 , 表示负数 , 而最低的3位是101 , 表示5 , 所以结果就是-5的原码了 , 而3+(-2)应该等于1 , 两者不符 。
如果负数的原码并不适用于减法操作 , 那该怎么办呢?这个问题的解答还要依赖计算机的溢出机制 。
我刚刚介绍了溢出以及取模的特性 , 我们可以充分利用这一点 , 对计算机里的减法进行变换 。假设有i-j , 其中j为正数 。如果i-j加上取模的除数 , 那么会形成溢出 , 并正好能够获得我们想要的i-j的运算结果 。如果我说的还是不太好理解 , 你可以参考下面这张图 。
我们把这个过程用表达式写出来就是i-j=(i-j)+(2^n-1+1)=i+(2^n-1-j+1) 。
其中2^n-1的二进制码在不考虑符号位的情况下是n-1位的1 , 那么2^n-1-2的结果就是下面这样的:
从结果可以观察出来 , 所谓2^n-1-j相当于对正数j的二进制原码 , 除了符号位之外按位取反(0变1 , 1变0) 。由于负数-j和正数j的原码 , 除了符号位之外都是相同的 , 所以 , 2^n-1-j也相当于对负数-j的二进制原码 , 除了符号位之外按位取反 。我们把2^n-1-j所对应的编码称为负数-j的反码 。所以 , -2的反码就是1111…1101 。
有了反码的定义 , 那么就可以得出i-j=i+(2^n-1-j+1)=i的原码+(-j的反码)+1 。
【什么是符号位如何让计算机理解哪些是正数 为什么手机要补码呢】如果我们把-j的反码加上1定义为-j的补码 , 就可以得到i-j=i的原码+(-j的补码) 。
由于正数的加法无需负数的加法这样的变换 , 因此正数的原码、反码和补码三者都是一样的 。最终 , 我们可以得到i-j=i的补码+(-j的补码) 。
换句话说 , 计算机可以通过补码 , 正确地运算二进制减法 。我们再来用3+(-2)来验证一下 。正数3的补码仍然是0000…0011 , -2的补码是1111…1110 , 两者相加 , 最后得到了正确的结果1的二进制 。
可见 , 溢出本来是计算机数据类型的一种局限性 , 但在负数的加法上 , 它倒是可以帮我们大忙 。

推荐阅读