机器数与真值
1.机器数:
一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号,正数为0,负数为1
栗子:
以8位整型数据为例
十进制中的+3在计算机中转换成二进制为 0000 0011
十进制中的-3在计算机中转换成二进制为 1000 0011
2.真值:
因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面有
符号数10000011,其最高位1代表负,其真正数值是-3而不是形式值131(10000011转换成十进制等于131).所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
栗子:
有符号位:
二进制 0000 0011 真值为 (+000 0011)3
二进制 1000 0011 真值为 (-000 0011)-3
无符号位:
二进制 1000 0011 真值为 (所见即真)131
原码,反码,补码
该注意的:
首先:确定这些码存在的意义——方便计算机计算减法(或者说处理负数)
其次:在正数原码反码补码都相同 (反码和补码是为了解决负数问题出现的,我认为没必要去强调为什么正数对应的这些码都相同,我查了半天资料没一个靠谱的。)
以下都用一Byte(8位)的数据来举例
原码
原码就是加了一位符号位的二进制数,正数符号位为0,负数符号位为1,符号位为最高位。
当前Byte数据八位:
| | | | | | | | |
|-符号位-|----------数据位-----------|
先将数的绝对值转换为二进制依照数据位往左用0补齐,最高位为符号位原数据正负在最左边一位换0或换1(此处需注意本身的数据长度)。
十进制 | 绝对值的二进制 | 补齐数据位 | 原码 |
---|---|---|---|
+3 | 11 | 000 0011 | 0000 0011 |
-3 | 11 | 000 0011 | 1000 0011 |
特殊的存在
十进制 | 绝对值的二进制 | 补齐数据位 | 原码 |
---|---|---|---|
+0 | 0 | 000 0000 | 0000 0000 |
-0 | 0 | 000 0000 | 1000 0000 |
反码
负数反码才有意义(文中讨论反码皆为负数)
简单的,负数反码就是对应正数的原码按位取反(0变1,1边0)。
十进制 | 对应正数的原码 | 反码 |
---|---|---|
-3 | 0000 0011 | 1111 1100 |
补码
负数补码才有意义(文中讨论补码皆为负数)
简单的,负数补码就是对应反码再加1(二进制下)。
十进制 | 对应正数的反码 | 补码 |
---|---|---|
-3 | 1111 1100 | 1111 1101 |
补码加减
使用原码进行计算的时候,对于人而言能够很轻易的辨别出符号位,然后直接对其他位数值进行计算。然而对于计算机的设计而言辨别出符号位就是一项非常复杂的工程,所以设计的时候就考虑让符号位直接参与计算,这样设计计算机就十分简单了。 对于加法而言符号位对于计算并没有影响,对于减法而言则考虑通过加上负数来转换为加法的方式进行计算。 如果通过原码来直接进行减法计算:
3 - 2
= 3 + (-2)
= 0000 0011 + 1000 0010(原)
= 1000 0101
= -5
结果显而易见,如果通过原码来直接让符号位参与运算的话是不正确的,所以为了解决减法的问题引入了补码的概念。
如果通过补码来进行减法计算:
3 - 2
= 3 + (-2)
= 0000 0011 + 1000 0010(原)
= 0000 0011 + 1111 1110(补)
= 1 0000 0001 去除溢出位
= 0000 0001
= 1
4 - 4
= 4 + (-4)
= 0000 0100 + 1000 0100(原)
= 0000 0100 + 1111 1100(补)
= 1 0000 0000 去除溢出位
= 0000 0000
= 0
-1 - 127
= (-1) + (-127)
= 1000 0001 + 1111 1111(原)
= 1111 1111 + 1000 0001(补)
= 1 1000 0000 去除溢出位
= 1000 0000
= -128(特殊的去除了原有的-0,变为了-128)
所以普遍的有符号8位Btye数据范围:-128~127
读书人都喜欢深入
那为什么补码计算可以非常巧妙的计算出结果呢?
我们主要要解决的问题就是负数的表示,而众所周知,绝对值相等的两个正负数之和为0。
假设我们有正数 0000 1111,我们如何表示其相反数呢?一般我们的思路是,找一个数,跟它相加的结果等于0,但是我们发现,要找出一个与它相加后结果等于0的数还是要略加思考一下的(因为要计算进位),所以,为何不找出一个与它相加后结果是11111 1111的数,然后该数+1即是我们所要的答案啦。
于是,很容易的:
0000 1111 + 1111 0000 + 1
= 1111 1111 + 1
= (1)0000 0000
一目了然,1111 0001 就是我们想要的答案了,那么我们是怎么得到这个相反数的呢?
首先,找出一个数与它加起来结果是全1的,这个数便是它的反码,然后这个数再加1,这便是它的相反数了,也是我们说的补码。
举个栗子:
原数 | 原码 | 反码 | 补码 |
---|---|---|---|
-3 | 1000 0011 | 1111 1100 | 1111 1101 |
3 | 0000 0011 | 0000 0011 | 0000 0011 |
3-3 = (1)0000 0000 = 0
由此,得到了负数的二进制编码由补码组成。
一个小小的例子解释了为何补码需要原码取反之后再加1,是不是很神奇?
在其他地方还看见将(-128~127)与0-255的映射表格如下:
0-255 | -128~127 | 二进制 |
---|---|---|
255 | -1 | 11111111 |
254 | -2 | 11111110 |
253 | -3 | 11111101 |
252 | -4 | 11111100 |
251 | -5 | 11111011 |
246 | -10 | 11110110 |
236 | -20 | 11101100 |
226 | -30 | 11100010 |
216 | -40 | 11011000 |
206 | -50 | 11001110 |
196 | -60 | 11000100 |
186 | -70 | 10111010 |
156 | -100 | 10011100 |
129 | -127 | 10000001 |
128 | -128 | 10000000 |
127 | 127 | 01111111 |
100 | 100 | 01100100 |
70 | 70 | 01000110 |
60 | 60 | 00111100 |
50 | 50 | 00110010 |
40 | 40 | 00101000 |
30 | 30 | 00011110 |
20 | 20 | 00010100 |
10 | 10 | 00001010 |
5 | 5 | 00000101 |
4 | 4 | 00000100 |
3 | 3 | 00000011 |
2 | 2 | 00000010 |
1 | 1 | 00000001 |
0 | 0 | 00000000 |
没有比人更高的山,没有比脚更远的路。