补码

2018-01-30 13:58:55


计算机中的符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同。

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

中文名 补码 外文名 two's complement representation 所属领域 计算机 作 用 存储数值

目录 1 特性

2 模 3 整数补码

▪ 正数

▪ 负数

▪ 转化为原码

▪ 补码的绝对值

4 小数补码求法

5 代数加减运算

▪ 补码加法

▪ 补码减法

▪ 补码乘法

6 代数解释

7 补码总结

特性 1、一个负整数(或原码)与其补数(或补码)相加,和为模。

2、对一个整数的补码再求补码,等于该整数自身。

3、补码的正零与负零表示方法相同。

模 模的概念可以帮助理解补数和补码。

“模”是指一个计量系统的计数范围。如时钟等。计算机也可以看成一个计量机器,它也有一个计量范围,即都存在一个“模”。例如:

时钟的计量范围是0~11,模=12。表示n位的计算机计量范围是0~2^(n)-1,模=2^(n)。

“模”实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。任何有模的计量器,均可化减法为加法运算。

例如:假设当前时针指向10点,而准确时间是6点,调整时间可有以下两种拨法:一种是倒拨4小时,即:10-4=6;另一种是顺拨8小时:10+8=12+6=6

在以12模的系统中,加8和减4效果是一样的,因此凡是减4运算,都可以用加8来代替。对“模”而言,8和4互为补数。实际上以12模的系统中,11和1,10和2,9和3,7和5,6和6都有这个特性。共同的特点是两者相加等于模。

对于计算机,其概念和方法完全一样。n位计算机,设n=8, 所能表示的最大数是11111111,若再加1成为100000000(9位),但因只有8位,最高位1自然丢失。又回了00000000,所以8位二进制系统的模为2^8。在这样的系统中减法问题也可以化成加法问题,只需把减数用相应的补数表示就可以了。把补数用到计算机对数的处理上,就是补码。

另外两个概念:()

用二进制表示正数不存在问题,但是在表示负数时会存在意想不到的困难。下面表中列出了用二进制数表示负整数的三个系统:

(一):ones' complement:这种表示法中,正数保持不变(因为这个方案就是要解决有效地将减法运算变成加负数的运算,所以,正数不需要变动,这里的反,就是相对于正数的二进制形式来说的),负数用公式 [1] (n为将符号位算在内的位数)计算。可以形象的将对应的正数的二进制形式的各个位取反即可。(这里和得到反码的步骤不一样。反码,补码,都是从原码开始操作得到。这里是从正数开始操作得到。但两者除了计算的起点不同,最终得到的编码形式是这样的。为了区别操作过程的不同,故仍然采用英文名。)

用四位二进制数做例子。那么-7的二进制(0111)各各位取反得到其ones complement数(1000)。就是其中最左边的一位为符号位。N=7 ,n=4,带入公式,得 =-7以及其二进制形式,过程如下:

2^{4}= 10000

减1 - 0001

01111 减7 - 0111

01000加粗的这部分呈现的是-7.

(二):twos complement:由于上面一种表示法 [1] (n为将符号位算在内的位数)

观察公式,twos complement数,相当于ones complement 数+1.

下面用4位二进制数来做例子:

2^{4}= 10000 2^{4}= 10000

减7 - 0111 减负7 - 1001

01001加粗部分表示-7 0 0111 加粗部分表示+7

十进制数

符号位+ 二进制绝对值 的表示方式    ones' complement    two's complement

+7 0111 表示方式不变 表示方式不变

+6 0110 表示方式不变 表示方式不变

+5 0101 表示方式不变 表示方式不变

+4 0100 表示方式不变 表示方式不变

+3 0011 表示方式不变 表示方式不变

+2 0010 表示方式不变 表示方式不变

+1 0001 表示方式不变 表示方式不变

+0 0000 表示方式不变 表示方式不变

-0 1000 1111 [1]0000

-1 1001 1110 1111

-2 1010 1101 1110

-3 1011 1100 1101

-4 1100 1011 1100

-5 1101 1010 1011

-6 1110 1001 1010

-7 1111 1000 1001

-8 超出4个bit所能表达范围 超出4个表达范围 1000

注: 要设计硬件区分符号位,比较绝对值大小。 无需设计硬件比较大小,但零存在两种表示方法。

较好的解决上述问题

。由于零只有一种表达方式,所以,可以比别的方式多表达一个-8.

符号绝对值的数表示方式

符号绝对值的数表示方式

Ones Complement Number representation

Ones Complement Number representation

twos_complement_number_representaion

twos_complement_number_representaion

整数补码

求给定数值的补码分以下两种情况:

正数 正整数的补码是其二进制表示,与原码相同[2] 。

【例1】+9的补码是00001001。(备注:这个+9的补码是用8位2进制来表示的,补码表示方式很多,还有16位二进制补码表示形式,以及32位二进制补码表示形式,64位进制补码表示形式等。每一种补码表示形式都只能表示有限的数字。)

负数 求负整数的补码,将其对应正数二进制表示所有位取反(包括符号位,0变1,1变0)后加1[2] 。

同一个数字在不同的补码表示形式中是不同的。比如-15的补码,在8位二进制中是11110001,然而在16位二进制补码表示中,就是1111111111110001。以下都使用8位2进制来表示。

【例2】求-5的补码。

-5对应正数5(00000101)→所有位取反(11111010)→加1(11111011)

所以-5的补码是11111011。

【例3】数0的补码表示是唯一的。

[+0]补=[+0]反=[+0]原=00000000

[ -0]补=11111111+1=00000000

转化为原码

已知一个数的补码,求原码的操作其实就是对该补码再求补码:

⑴如果补码的符号位为“0”,表示是一个正数,其原码就是补码。

⑵如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。

【例4】已知一个补码为11111001,则原码是10000111(-7)。

因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”。

其余七位1111001取反后为0000110;

再加1,所以是10000111。

补码的绝对值

【例5】-65的补码是10111111

若直接将10111111转换成十进制,发现结果并不是-65,而是191。

事实上,在计算机内,如果是一个二进制数,其最左边的位是1,则我们可以判定它为负数,并且是用补码表示。

若要得到一个负二进制补码的数值,只要对补码全部取反并加1,就可得到其数值。

如:二进制值:10111111(-65的补码)

各位取反:01000000

加1:01000001(+65)

小数补码求法

一种简单的方式,符号位保持1不变,数值位从右边数第一个1及其右边的0保持不变,左边按位取反。

代数加减运算

补码加法

[X+Y]补 = [X]补 + [Y]补

【例6】X=+0110011,Y=-0101001,求[X+Y]补

[X]补=00110011 [Y]补=11010111

[X+Y]补 = [X]补 + [Y]补 = 00110011+11010111=00001010

注:因为计算机中运算器的位长是固定的(定长运算),上述运算中产生的最高位进位将丢掉,所以结果不是100001010,而是00001010,。

补码减法

[X-Y]补 = [X]补 - [Y]补 = [X]补 + [-Y]补【1】

【例7】1-1 [十进制]

1的原码00000001 转换成补码:00000001

-1的原码10000001 转换成补码:11111111

1+(-1)=0

00000001+11111111=00000000

00000000转换成十进制为0

0=0所以运算正确。

【例8增】-7-(-10) [十进制]

改为加法形式:-7-(-10)=-7+(-(-10))

-7的补码:11111001

-(-10)的补码:-10的原码为10001010,-(-10)的原码为00001010,

-(-10)的补码就是其原码,为00001010

-7 - (-10)= -7 + 10 = 3

11111001+00001010 = 00000011

转换成十进制为3

补码乘法

补码的乘法不具备【X*Y】补=【X】补×【Y】补的性质。但是【X*Y】补==【X】补×Y,所得结果再取补码,如x=101,y=011,[x*y]补=-[(-101)*011]=-[011*011]=-01001=10111

其中,若【Y】补=y31y30……y0,则 Y=-y31*2^31+y30*2^30+……+y0*2^0

代数解释

在十进制中我们可以把n位二进制体系中的数

a表示为:

求补码,意味着求:

而根据等比数列求和公式:

则 因为这里k0,k1,k2,k3……不是0就是1,所以1-k0,1-k1,1-k2的运算就是二进制下的取反

注:n位二进制,最高位为符号位,因此表示的数值范围-2^(n-1) ——2^(n-1) -1,所以模为2^n。上面提到的8位二进制模为2^8是因为最高位非符号位,表示的数值范围为0——2^8-1。

补码总结

补码只是一种相对合理的编码方案。这个方案在负数的机器表示中解决了3个问题:

数的表示

在数的表示上通过人为的定义来消除编码映射的不唯一性,对转换后的10000000强制认定为-128。当然对原码和反码也可以做这种强制认定,那为什么原码和反码没有流行起来?原码和反码没有流行起来,是因为在数的运算上对符号位的处理无法用当时已有的机器物理设计来实现。由于原码和反码在编码时采用了硬性的人工设计,这种设计在数理上无法自动的通过模来实现对符号位的自动处理,符号位必须人工处理,必须对机器加入新的物理部件来专门处理符号位,这加大了机器设计难度,加大的机器成本,不到万不得已,不走这条路。

数的运算

设计补码时,有意识的引用了模运算在数理上对符号位的自动处理,利用模的自动丢弃实现了符号位的自然处理,仅仅通过编码的改变就可以在不更改机器物理架构的基础上完成的预期的要求,所以补码沿用至今。

自身逻辑意义的完整性

补码这个编码方案要解决的是如何在机器中表示负数,其本质意义为用一个正数来表示这个正数对应的负数。所谓-20的补码是指:如何在机器中用补码形式表示-20。具体过程是这样的:将20的二进制形式直接写出00010100,然后所有位取反变成11101011,再加1变成了11101100。最简单的补码转换方式,不必去理会转换过程中的符号位,只关注转换前和最终转换后的符号位就行了。

那么对11101100求出其补码又具有什么现实含义呢?对一个数求补,逻辑过程是对这个数的所有的二进制位按位取反再加1。现实含义是求出这个数对应的负数形式。对11101100求补就是求出这个数对应的负数的形式,直接操作下11101100,先所有位取反00010011,再加上1就成了00010100。对11101100求出其补码的含义:11101100按照现行补码码制表示的有符号数是-20,对于-20求补就是求出其对应的负数-(-20),现实中-(-20)是+20,那么求补运算的结果符合现实情况吗,00010100转换成有符号数正是+20,这就说明了补码自身逻辑意义是完整的,是不会自相矛盾的。

最后,补码的总前提是机器数,不要忘了机器数的符号位含义,最高位为0表示正数,最高位为1表示负数,而最高位是指机器字长的最左边一位。字节数100B,最高位为00000100中的最左边的0。

【1】 在上一个版本中有如下说明:

“其中[-Y]补 称为负补,求负补的方法是:负数的绝对值的原码所有位按位取反;然后整个数加1。(恢复本来解释。请路人真正理解并实际验证后再修改。以免误导大众。另外,例6不具典型性,新增例7。)”

私以为, 不必要提出负补的概念以使问题复杂化,尽管该解法是正确的,但却完全没有必要增加新的运算方法及运算结构。求[-Y]补,只需,先将符号位取反,求出-Y, 再求-Y的补码即可。尽管这与求负补的方法实际上是一致的, 但是却简化了概念,仅仅是对过去概念以及运算结构的复用。