参考1:https://www.imooc.com/article/16813?block_id=tuijian_wz
参考2:https://www.cnblogs.com/yilang/p/11179509.html
基本概念
1、机器数:
一个数在计算机中的二进制表现形式,叫做这个数的机器数。
机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1。
机器数有多种编码方式。例如,计算机字长为8位,采用原码编码方式表示机器数如下:
> 十进制数 +3 ,机器数是 0000 0011。
> 十进制数 -3 ,机器数是 1000 0011。
2、真值:
机器数第一位为符号位,其余位直接换算后得到的即为机器数的 真值。
二进制数第一位不是符号位,所有位直接换算后得到的为二进制数的 形式值。
> 机器数 0000 0011 真值是 3,二进制数 0000 0011形式值是 3.
> 机器数 1000 0011 真值是-3,二进制数 1000 0011形式值是 131.
需要解决的问题:采用某种编码方式解决机器数的运算问题。
由于机器数是带符号数,符号位需要参与运算,又必须保证结果正确,需要采用何种编码方式呢?原码、反码、补码正是为了解决计算机中机器数的运算问题。
原码
原码是最简单的机器数表示法。
原码:用最高位表示符号位,‘1’表示负号,‘0’表示正号。其他位存放该数的绝对值的二进制。
例如:
>[+1]原 = 0000 0001
>[+2]原 = 0000 0010
>[+3]原 = 0000 0011
>[-1]原 = 1000 0001
>[-2]原 = 1000 0010
>[-3]原 = 1000 0011
采用原码编码的机器数进行机器运算:存在问题!
>[+1]原 + [+2]原 = 0000 0011 = [+3]原 //运算结果正确
>[-1]原 + [-2]原 = 0000 0011 = [+3]原 //运算结果错误!!
>[+1]原 + [-2]原 = 1000 0011 = [-3]原 //运算结果错误!!
>[-1]原 + [+2]原 = 1000 0011 = [-3]原 //运算结果错误!!
>[+1]原 + [-1]原 = 1000 0010 = [-2]原 //运算结果错误!!
根本原因:
如果采用原码编码方式作为机器数,(+0)机器数与(-0)机器数表示结果不相同!无法直接参与机器运算!!
> [+0]原 = 0000 0000
> [-0]原 = 1000 0000
解决方式:补码!
反码
了解反码前先认识反码。
反码:正数的反码=正数的原码。负数的反码=负数原码的符号位+负数原码的其余位按位取反。
例如:
>[+1]原 = 0000 0001
>[+1]反 = 0000 0001
>
>[+2]原 = 0000 0010
>[+2]反 = 0000 0010
>
>[+3]原 = 0000 0011
>[+3]反 = 0000 0011
>
>[-1]原 = 1000 0001
>[-1]反 = 1111 1110
>
>[-2]原 = 1000 0010
>[-2]反 = 1111 1101
>
>[-3]原 = 1000 0011
>[-3]反 = 1111 1100
>
采用反码编码的机器数进行机器运算:存在问题:
>[+1]反 + [+2]反 = 0000 0011 = [+3]反 //运算正确
>[-1]反 + [-2]反 = 1111 1011 = [-5]反 //运算错误!!
>[+1]反 + [-2]反 = 1111 1110 = [-1]反 //运算正确
>[-1]反 + [+2]反 = 0000 0000 = [+0]反 //运算错误!!
>[-1]反 + [+1]反 = 1111 1111 = [-0]反 //运算??
根本原因:
如果采用反码编码方式作为机器数,(+0)机器数与(-0)机器数表示结果不相同!无法直接参与机器运算!!
>[+0]反 = 0000 0000
>[-0]反 = 1111 1111
解决方式:补码!
补码
补码:正数的补码 = 正数的原码。负数的补码 = 负数的反码 + 1。
《计算机组成原理中》,补码的另外一种算法是(0除外):负数的补码等于他的原码自低位向高位,尾数的第一个‘1’及其右边的‘0’保持不变,左边的各位按位取反,符号位不变。
例如:
>[+1]原 = 0000 0001
>[+1]反 = 0000 0001
>[+1]补 = 0000 0001
>
>[+2]原 = 0000 0010
>[+2]反 = 0000 0010
>[+2]补 = 0000 0010
>
>[+3]原 = 0000 0011
>[+3]反 = 0000 0011
>[+3]补 = 0000 0011
>
>[-1]原 = 1000 0001
>[-1]反 = 1111 1110
>[-1]补 = 1111 1111
>
>[-2]原 = 1000 0010
>[-2]反 = 1111 1101
>[-2]补 = 1111 1110
>
>[-3]原 = 1000 0011
>[-3]反 = 1111 1100
>[-3]补 = 1111 1101
采用补码编码的机器数进行机器运算:运算正确!
>[+1]补 + [+2]补 = 0000 0011 = [+3]补 //运算正确
>[-1]补 + [-2]补 = 1111 1101 = [-3]补 //运算正确
>[+1]补 + [-2]补 = 1111 1111 = [-1]补 //运算正确
>[-1]补 + [+2]补 = 0000 0001 = [+1]补 //运算正确
>[-1]补 + [+1]补 = 0000 0000 = [+0]补 //运算正确
验证:[+0]补 ?= [-0]补
>[+0]补 = 0000 0000
>[-0]补 = [-0]反 + 1 = 1111 1111 + 0000 0001 = 0000 0000 = [+0]补
结论:[+0]补 = [-0]补 = 0000 0000
一些常用的补码:
[+0]补 = 0000 0000
[+1]补 = 0000 0001
[+2]补 = 0000 0010
...
[+126]补 = 0111 1110
[+127]补 = 0111 1111 = 2^7 - 1
[-128]补 = 1000 0000 = -2^7
[-127]补 = 1000 0001
...
[-2]补 = 1111 1110
[-1]补 = 1111 1111
4bit补码环形示意图:
4bit原码、反码、补码环形示意图:
原理分析:
同余的概念:
两个整数a,b,若它们除以整数m所得的余数相等,则称a,b对于模m同余
记作 a ≡ b (mod m)
读作 a 与 b 关于模 m 同余。
例如:
2%7 = 2
9%7 = 2
2 ≡ 9 (mod 7)
2 与 9 关于模 7 同余。
互补数:
在有模的计量系统中,当某个值A, 需要做一个减法运算(A - B = X),得到某个想要的结果X时。我们可以化减为加,使得A + C也能得到想要的结果X。那么B和C就是互为补数,他们相加得到的值就是该计量系统的模,减B和加C的行为是同余的,既(A - B) mod 模 = X ,(A + C) mod 模 = X。
例如:
在模为8的计量系统中:
5 - 2 = (5 +(2的补数))(mod 8) = (5 +(8-2))(mod 8) = (5 + 6)(mod 8) = 3
采用模与同余的概念来理解补码的概念:
机器数解决符号参加计算的解决思路是:减去一个数 = 加上这个数的补数。
对于4bit的表示系统,模为16(0~15):
7 - 5
= (7 + (5的补数))mod(16)
= (7 + (16-5))mod(16)
= (7(原) + 11(原))mod(16) //......(1)
= 7 + (-5) //......(2)
= 2
从原码的加法运算结果得知,采用原码进行加法运算可以得到正确结果。从(1)(2)可以得到,可以用11(原)表示(-5),而(-5)有自己的原码、反码,对(-5)新的编码方式称之为(-5)的**“补码” - - 补数的原码**。