提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
因为一直不是很清楚原码反码的运算和符号位的关系,故想借此机会一举打好计算机数据表示与处理的基础。这里并不讨论这些概念的严格定义,仅仅从个人角度提出理解。
一、原码、反码、移码、补码的概念
计算机中表示数据的方式有两种,分别是无符号数和有符号数。对于无符号数,其实没什么好说的,就全都是正数和0。而对于有符号数来说,原码一般是这个数的二进制表示加上符号位,其中最高位表示符号位。如+7的原码是0 111,最前面的0是符号位,而-7的原码则是1 111,在有符号数中,通常用0表示正号,用1表示负号。
对于一个8位的二进制数来说,原码的表示范围是-127~+127,其中0有两种表示方法,+0和-0。
反码也非常简单,就是原码的符号位不变,将所有二进制位取反即可,如+7的反码是0 000 。反码在实际中并没有什么用,通常用来过渡求补码。
为了计算简便,人们引出了补码的概念,对二进制补码来说,求一个数的补码,就相当于对原码取反+1,符号位不变,如+7的补码是0 001.求补码还有一个快捷方法,就是将原码从右边数第一个1的左边,全部取反,而第一个1自身以及这个1的右边则保持不变,符号位保持不变,如求0 110101001000的补码为:0 001010111000,可以发现加粗的的地方取反,而未加粗的地方不变,符号位也保持不变。
在浮点数中,通常需要对浮点数的位阶比较大小,为了方便比较,就将负数和正数都加上一个偏置值使其全都变为正数,以此来保证比较的速度。这个偏置值通常跟位数有关,通常是2n或2n-1。比如对于一个3位的二进制数,偏置值通常为7或者8。需要注意的是,移码中符号位是参与运算的。
二、深入理解原码和补码的转换
我们都知道,减去一个数等于加上这个数的补码,为什么会这样呢?我们先看看原码的表示。这里以4位二进制数为例子,对于有符号数来说,原码的表示范围是-7到+7,也就是0000到0111一共8个数字,而补码仍然是4位,我们思考一下,正数的补码仍然是正数,说明正数补码占用了+0到+7,也就是0000到0111一共8个二进制表示,而负数占用了-0到-7,也就是从1000到1111也是8个二进制表示。他们的对应关系是怎么样的呢?
真值 | 原码 | 补码 |
---|---|---|
… | … | … |
+6 | 0110 | 0110 |
+7 | 0111 | 0111 |
-8 | - | 1000 |
-7 | 1111 | 1001 |
-6 | 1110 | 1010 |
-5 | 1101 | 1011 |
-4 | 1100 | 1100 |
-3 | 1011 | 1101 |
-2 | 1010 | 1110 |
-1 | 1001 | 1111 |
可以发现,补码就是在正数增大到极限后,从最小的负数开始增加。现在的计算机通常以补码的方式储存数据,这样做的好处是,对任意两个数,无论这两个数是正数还是负数,当他们做加减的运算的时候,只需要将其加起来就可以了,加减法统一使用补码加法解决。
当一个数需要减去一个数的时候,就相当于加上这个数的负数。如4-5=4+(-5)。计算机并不在意这两个数的正负,直接将这两个数的补码相加,最后得到的结果仍为补码,运算结果如下:
0100
1011(-5的补码)
---------------------
1111(-1的补码)
由于有效范围是-8到+7,因此经过补码运算后4-5得到的结果是-1