一文搞懂原码、反码、补码、移码

  • 原码:正数是其二进制本身;负数是符号位为1,数值部分取X绝对值的二进制。
  • 反码:正数的反码和原码相同;负数是符号位为1,其它位是原码取反。
  • 补码:正数的补码和原码,反码相同;负数是符号位为1,其它位是原码取反,未位加1。(或者说负数的补码是其绝对值反码未位加1)
  • 移码:将符号位取反的补码(不区分正负)

正数的原码、反码、补码相同

举个栗子以一个字节8位说明:

编码(十进制) 22 -22
原码 010110 110110
反码 010110 101001
补码 010110 101010
移码 110110 001010

注:红色为符号位

1. 根据补码求原码

已知一个数的补码,求原码的操作分两种情况:

  1. 如果补码的符号位为“0”,表示是一个正数,所以补码就是该数的原码。
  2. 如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:符号位为1;其余各位取反,然后再加1

2. 补码加、减运算公式

在做补码加减法时,只需将符号位和数值部分一起参与运算,并且将符号位产生的进位丢掉即可

  1. 补码加法公式
1
[X+Y]补 = [X]补 + [Y]补
  1. 补码减法公式
1
[X-Y]补 = [X]补-[Y]补 = [X]补 + [-Y]补

其中:[-Y]补称为负补,求负补的办法是:对补码的每一位(包括符合位)求反,且未位加1

3. 为何要使用原码, 反码和补码

首先我们知道计算机可以用三种编码表示一个数,对于正数:

1
[+1] = [00000001]原 = [00000001]反 = [00000001]补

不需要过多解释,但是对于负数:

1
[-1] = [10000001]原= [11111110]反= [11111111]补

可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢?

因为对于人而言可以知道第一位表示符号位,但是对于计算机而言,是无法区别的,想要计算机区别就必须增加一些额外的标记,这样会对设计造成一定的复杂性,
于是,聪明的人们开始探索,能不能将符号位也参与运算呢,首先来看原码

1
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原= [10000010]原 = -2

很显然对于负数的加法,原码计算是错误的,为了解决这个问题,出现了反码

1
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反+ [1111 1110]反= [1111 1111]反= [1000 0000]原= -0

计算之后发现结果貌似没有问题,但是符号位有一点点问题,出现了-0,这就有可能出现+0和-0两个编码,都表示0,这样还是有问题,于是出现了补码

1
(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补+ [1000 0001]补= [1000 0000]补

发现用了补码之后,解决了所有问题,并且还比其他两个编码方式多表示了一位负数-128,所以在同样长度的计算机中,补码会比其他两个编码多表示一位数字

4.移码的作用

移码(又叫增码或偏置码)通常用于表示浮点数的阶码,其表示形式与补码相似,只是其符号位用“1”表示正数,用“0”表示负数,数值部分与补码相同。

  1. 移码的第一个作用就是方便比较大小
    十进制 补码 移码
    -128 10000000 00000000
    -127 10000001 00000001
    -126 10000010 00000010
    -1 11111111 01111110
    0 00000000 10000000
    1 00000001 10000001
    127 01111111 11111111

通过这个表格你会发现当十进制逐渐增大时,只有对应的移码是逐渐增大的(把符号位也当作数值位看,因为计算机不会区分符号位)

  1. 第二个作用就是浮点数的表示
  2. …………

其实是我也不会!!!