原码、反码、补码

介绍

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

原码

原码(true form)是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。

优点:
简单直观;例如,我们用8位二进制表示一个数,+11的原码为00001011,-11的原码就是10001011

缺点:
原码不能直接参加运算,可能会出错。例如数学上,1+(-1) = 0,而在二进制中00000001+10000001=10000010,换算成十进制为-2。显然出错了。

反码

反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。

补码

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

为什么八位二进制数表示范围为-128~+127?

首先八位二进制数0000 0000 ~1111 1111,一共可以表示28=256位数,如果表示无符号整数可以表示0~255。计算方法就是二进制与十进制之间的转换。

如果想要表示有符号整数,就要将最前面一个二进制位作为符号位,即0代表正数,1代表负数,后面7位为数值域,这就是原码定义。这样在现实生活中完全没有问题,但在计算机中就出现了问题。

  1. 数的表示

    在原码中,0的表示有两种(+0)0000 0000、(-0)1000 0000,这样就产生了编码映射的不唯一性,在计算机上就要区分辨别。然而+0、-0却没有什么现实意义。

  2. 数的运算

    为了解决上述数的表示问题,我们可以强制把转换后的10000000强制认定为-128。但这又出现了一个新的问题就是数的运算。数学上,1+(-1)=0,而在二进制中00000001+10000001=10000010,换算成十进制为-2。显然出错了。所以原码的符号位不能直接参与运算,必须和其他位分开,这就增加了硬件的开销和复杂性。
    这个时候就要引入补码,补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。反码定义为:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。

问题1:为什么要引入补码呢?

先解决第一个问题,引入补码是为了解决计算机中数的表示和数的运算问题,使用补码,可以将符号位和数值域统一处理,即引用了模运算在数理上对符号位的自动处理,利用模的自动丢弃实现了符号位的自然处理,仅仅通过编码的改变就可以在不更改机器物理架构的基础上完成的预期的要求。

问题2:负数补码定义为什么是相对应的正数原码取反加一?

要解决第二个问题同时理解补码,首先要理解“模”。

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

“模”是指一个计量系统的计数范围。如时钟等。计算机也可以看成一个计量机器,它也有一个计量范围,即都存在一个“模”。例如:
时钟的计量范围是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位二进制系统的模为29。在这样的系统中减法问题也可以化成加法问题,只需把减数用相应的补数表示就可以了。把补数用到计算机对数的处理上,就是补码。

接下来就是取反加一的来源:

例如-8,可以看做0-8,即0000 0000 - 0000 1000,小减大,向高位借一,即1 0000 0000 - 0000 1000 = 1111 1000,这个可以看做用模数来减去该数,会得到该数的补数。同时上式也可以看做 (1111 1111 - 0000 1000)+1,即0000 1000 取反加1。

负数补码定义是相对应的正数原码取反加一,这个同负数的反码末尾加一是同样的效果。注意看反码的定义。取反加一是逐位取反,包括符号位。

对一个正数的原码取反加一,得到这个正数对应负数的补码。例如~6=-7,而且加一之后会多出一个八进制补码1000 0000,而这个补码就对应着原码1000 0000,数字位同时当做符号位即-128。

根据以上内容我们就可以来解释八位二进制数的表示范围

八位二进制正数的补码范围是0000 0000 ~ 0111 1111 即0 ~ 127,负数的补码范围是正数的原码0000 0000 ~ 0111 1111 取反加一(也可以理解为负数1000 0000 ~ 1111 1111化为反码末尾再加一)。

所以得到 1 0000 0000 ~ 1000 0001,1000 0001作为补码,其原码是1111 1111(-127),依次往前推,可得到-1的补码为1111 1111,那么补码0000 0000的原码是1000 0000符号位同时也可以看做数字位即表示-128,这也解释了为什么127(0111 1111)+1(0000 0001)=-128(1000 0000)。

总结: 在计算机中数据用补码表示,利用补码统一了符号位与数值位的运算,同时解决了+0、-0问题,将空出来的二进制原码1000 0000表示为-128,这也符合自身逻辑意义的完整性。因此八位二进制数表示范围为-128~+127。在计算机运算的时候,都是以补码的方式来运算的。

计算机内部运算的实质是进行补码运算,接下来举例说明
假如 A = 60, B = 13

A+B
A的原码为: 0011 1100   
A的反码为: 0011 1100
A的补码为: 0011 1100
B的原码为: 0000 1101  
B的反码为: 0000 1101
B的补码为: 0000 1101
A + B
    0011 1100
    0000 1101
--------------
    0100 1001
    
0100 1001转换为10进制整数就是73
    
A-B = A + (-B)
A的原码为: 0011 1100   
A的反码为: 0011 1100
A的补码为: 0011 1100
-B的原码为: 1000 1101  
-B的反码为: 1111 0010
-B的补码为: 1111 0011
A - B = 
     0011 1100
     1111 0011
--------------
     0010 1111

0010 1111转换为10进制整数就是47

需要注意的是如果得到的结果是正数,则补码就是原码,但是如果得到的结果是负数,则需要将补码-1取反变成原码后再转换成整数
B - A    
-A的原码为: 1011 1100
-A的反码为: 1100 0011
-A的补码为: 1100 0100
B的原码为: 0000 1101  
B的反码为: 0000 1101
B的补码为: 0000 1101
B - A =     
    1100 0100
    0000 1101
--------------
    1101 0001
根据补码符号位可以看出结果为负数,所以需要先-1转换为反码1101 0000,然后符号位不变,取反为原码为1010 1111即为-47   

参考:
为什么八位二进制数表示范围为-128~+127?

原文地址:https://www.cnblogs.com/itbsl/p/9851149.html