相关概念
真值
符合人类习惯的数字
机器数
一个数在计算机的存储形式是二进制数,我们称这些二进制数为机器数,机器数是有符号,在计算机中用机器数的最高位存放符号位,0表示正数,1表示负数。
机器数的真值
因为带有符号位,所以机器数的形式值不等于其真值,以机器数1000 0111为例,其真正表示的值为-7,而形式值为135。将带符号的机器数的真正表示的值称为机器数的真值。
原码
原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值,例如的十进制的的正负1,用8位二进制的原码表示如下:
反码
反码的表示方法为:
- 正数的反码是其原码本身。
- 负数的反码是在其原码的基础上,符号位不变,其余各位取反。
$[1]反=[1]原 \ [-1]_反=(11111110)_2$
补码(数据在计算机中的存储形式)
反码加一,只是补码所具有的一个性质,不能被定义成补码。负数的补码,是能够和其相反数相加通过溢出从而使计算机内计算结果变为0的二进制码(即二进制意义下的相反数)。
引用自万能网友
补码的编码方式为:
- 正数的补码是其原码本身。
- 负数的补码是在其反码的基础上,加 1。
$[1]补=[1]原 \ [-1]补=[-1]反+1=(11111111)_2$
设计理念
为什么使用补码作为数据在计算机中的存储形式
1.保证 0 的唯一性
原码和反码,0 都有 +0 和 -0 两种编码,这违背了编码唯一性的原则[1]。
但是对于补码来说,+0 和 -0 均指向 $(00000000)_2$[2]
2.能多出来 1 个数字
在上一条中已经提出了,0 被唯一指向为 $(00000000)_2$ ,那么就多出了一种指向 $(10000000)_2$[3]可以用来表示 -128
3.能正确进行负数运算
原码和反码的运算缺陷
原码:$1+(-1)=(00000001)_2+(10000001)_2=(10000010)_2=-2$
反码: $(+0)+(-0)=(00000000)_2+(11111111)_2=(11111111)_2=-0$
由上述例子可见原码和反码在减法上均有问题
补码的诞生
此时为了计算机在底层能尽可能的减少分支判断,补码就被设计出来了。
下面就补码运算的正确性进行验证:
首先来看下大家生活中常见的时钟,我们发现时钟顺时针转和逆时针转似乎能达到一样的效果。那么我们可以看出在时钟中 +10 和 -2 是等价的。(仅仅在时钟上看的时针、分针和秒针)
那么在二进制中是否能进行类似的操作,把负数变换成一个等价的正数。在此之前我们需要引入 同余的概念(就是上面时钟的原理)
可以看见 13 和 1是 同余的,而 13=10+3,1=-2+3 ,因此可看出可以把 -2 变成 +10
引用上面的方法,我们可以把二进制的负数进行变化,变化为对应的正数,从而实现把减法变加法的操作。
下面开始讲述如何进行把二进制的负数进行变化
此时补充一点:计算机中以 8位二进制数为基本单位,超过八位的数字只会保留最后八位,前面的位数被自然舍弃了。这其实就是取余的思想。
由$\ -x\equiv m-x \ (mod\ m)$ 可知,负数的二进制编码$=(100000000)_2-$原码。这个二进制编码就是补码
现在负数的运算只要转化为补码:就可以进行加法操作了。这也就是补码的定义:负数的补码,是能够和其相反数相加通过溢出从而使计算机内计算结果变为0的二进制码。(反码加一,只是补码所具有的一个性质,不能被定义成补码。)