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


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

什么是符号位?为什么要有符号位?
首先我们来看 , 什么是符号位 , 为什么要有符号位?用一句话来概括就是 , 符号位是有符号二进制数中的最高位 , 我们需要它来表示负数 。
在实际的硬件系统中 , 计算机CPU的运算器只实现了加法器 , 而没有实现减法器 。那么计算机如何做减法呢?我们可以通过加上一个负数来达到这个目的 。比如 , 3-2可以看作3+(-2) 。因此 , 负数的表示对于计算机中的二进制减法至关重要 。
那么 , 接下来的问题就是 , 如何让计算机理解哪些是正数 , 哪些是负数呢?为此 , 人们把二进制数分为有符号数(signed)和无符号数(unsigned) 。
如果是有符号数 , 那么最高位就是符号位 。当符号位为0时 , 表示该数值为正数;当符号位为1时 , 表示该数值为负数 。例如一个8位的有符号位二进制数10100010 , 最高位是1 , 这就表示它是一个负数 。
如果是无符号数 , 那么最高位就不是符号位 , 而是二进制数字的一部分 , 例如一个8位的无符号位二进制数10100010 , 我们可以通过第1讲讲过的内容 , 换算出它所对应的十进制数是162 。由于没有表示负数的符号位 , 所有无符号位的二进制都代表正数 。
有些编程语言 , 比如Java , 它所有和数字相关的数据类型都是有符号位的;而有些编程语言 , 比如C语言 , 它有诸如unsignedint这种无符号位的数据类型 。
下面我们来看 , 什么是溢出?
在数学的理论中 , 数字可以有无穷大 , 也有无穷小 。可是 , 现实中的计算机系统 , 总有一个物理上的极限(比如说晶体管的大小和数量) , 因此不可能表示无穷大或者无穷小的数字 。对计算机而言 , 无论是何种数据类型 , 都有一个上限和下限 。
在Java中 , int型是32位 , 它的最大值也就是上限是2^31-1(最高位是符号位 , 所以是2的31次方而不是32次方) , 最小值也就是下限是-2^31 。而long型是64位 , 它的最大值 , 也就是上限是2^63-1;最小值 , 也就是下限是-2^63 。
对于n位的数字类型 , 符号位是1 , 后面n-1位全是0 , 我们把这种情形表示为-2^(n-1) , 而不是2^(n-1) 。一旦某个数字超过了这些限定 , 就会发生溢出 。如果超出上限 , 就叫上溢出(overflow) 。如果超出了下限 , 就叫下溢出(underflow) 。
那么溢出之后会发生什么呢?我以上溢出为例来给你解释 。
n位数字的最大的正值 , 其符号位为0 , 剩下的n-1位都为1 , 再增大一个就变为了符号位为1 , 剩下的n-1位都为0 。而符号位是1 , 后面n-1位全是0 , 我们已经说过这表示-2^(n-1) 。
那么就是说 , 上溢出之后 , 又从下限开始 , 最大的数值加1 , 就变成了最小的数值 , 周而复始 , 这不就是余数和取模的概念吗?下面这个图可以帮助你的理解 。
其中右半部分的虚线表示已经溢出的区间 , 而为了方便你理解 , 我将溢出后所对应的数字也标在了虚线的区间里 。由此可以看到 , 所以说 , 计算机数据的溢出 , 就相当于取模 。而用于取模的除数就是数据类型的上限减去下限的值 , 再加上1 , 也就是(2^(n-1)-1)-(-2^(n-1))+1=2x2^(n-1)-1+1=2^n-1+1 。
你可能会好奇 , 这个除数为什么不直接写成2^n呢?这是因为2^n已经是n+1位了 , 已经超出了n位所能表示的范围 。
二进制的原码、反码及补码
理解了符号位和溢出 , 我接下来说说 , 什么是二进制的原码、反码和补码 , 以及我们为什么需要它们 。
原码就是我们看到的二进制的原始表示 。对于有符号的二进制来说 , 原码的最高位是符号位 , 而其余的位用来表示该数字绝对值的二进制 。所以+2的原码是000…010 , -2的的原码是100.…010 。
那么我们是不是可以直接使用负数的原码来进行减法计算呢?答案是否定的 。我还是以3+(-2)为例 。

推荐阅读