数值类型
数值类型
本节主要讨论数值类型在计算机系统中的底层表示。
原码,反码与补码
一个数在计算机中的表现形式叫做机器数,这个数有正负之分,在计算机中用一个数的最高位(符号位)用来表示它的正负,其中
原码的编码较为直观,用第一位表示符号,其余位表示值。因为第一位是符号位,所以[1111_1111, 0111_1111]
即[-127, 127]

原码计算。中可以看见左边每增加一个二进制单位对应的真数是递减的,而右边每增加一个二进制单位对应的真数是递增的,所以对于原码来说,能满足正数的加法,但无法满足负数的加法
2+1=[0000_0010]原+[0000_0001]原=[0000_0011]原=3
1+-1=[0000_00001]原+[1000_0001]原=[1000_0010]原=-2
为了满足负数对加法的需求,就必须让负数与他对应的二进制码是同步递增或者同步递减于是就通过符号位不变,其余位取反来满足这个同步递增或者递减的要求,由于正数本来就满足它本身的加法,所以不需要做任何改变。这就是反码的定义由来。
-2+1=[1111_1101]反+[0000_0001]反=[1111_1110]反=-1
127+1=[1000_0000]反=-127=128
-1+2=[1111_1110]反+[0000_0010]反=[0000_0000]反=0
但是这里有个不合理的地方,就是 [1111_1111]
和 [0000_0000]
都表示[1111_1111]
和 [0000_0000]
合并,由于[1111_1111]+[0000_0001]=[0000_0000]
补码定义如下:
- 正数的补码为其本身,负数补码除了符号位将所有位置的数字取反,再加
1. - 符号位权的总和,符号位权值为
2 的n 次方,最高位权值带符号 - 数字系统的模减去数字本身得出的数字就是补码
从上面的图中发现还有一个 [1000_0000]
的二进制没有对应任何真数,于是就规定了这个数的真数是[-128~127]
,这样一来(x+128)mod 256 - 128
。
定数
浮点类型
计算机系统中直接以二进制形式存储和表达整数,但是对于浮点数而言,计算机本身并不识别小数点,也就导致了无法直接存储浮点数。历史上计算机科学家们曾提出过多种解决方案,最终获得广泛应用的是
IEEE 754
前文介绍的定点数中的定点指的是约定小数点位置固定不变,然后对数字进行表示。那浮点数的浮点含义也就容易理解了:在对数字进行表示时,小数点的位置可以是漂浮不定的。浮点数采用一种科学计数法的方式表示,如果要表示十进制小数
8.345 = 8.345 * 10^0
8.345 = 83.45 * 10^-1
8.345 = 834.5 * 10^-2
...
同样,对于二进制数,也可以用科学计数法表示,把基数
X = (-1)^S * M * R^E

其中各变量的含义如下:
- S:取值
0 或1 ,决定一个数字的符号,0 表示正,1 表示负 - M:二进制定点小数,表示数字的尾数
- E:二进制定点整数,表示数字的阶码或指数
- R:基数,可以约定为
2 、4、16

为了使得表示的数字范围、精度最大化,浮点数标准还对阶码和尾数进行了规定:
-
尾数的第一位总是
1 ,因此可在尾数中省略第一位的1 ,这个1 称为隐藏位,使得单精度23 位尾数表示了24 位有效数字,双精度52 位尾数表示了53 位有效数字。 -
阶码不是用单纯的移码表示,而是在移码的基础上进行偏移修正,因为尾数第一位
1 在隐藏位中,所以阶码的移码需要加1 ,即阶码为(2^n-1)-1
。
当然,虽然规定了阶码和尾数的位数,但阶码和尾数有几种情况,分别表示不同的值:
-
E 不全为0 或不全为1 。这时,浮点数就采用上面的规则表示,即指数E 的计算值减去127 (或1023 ) ,得到真实值,再将有效数字M 前加上第一位的1 。 -
E 全为0 。这时,浮点数的指数E 等于1-127 (或者1-1023 ) ,有效数字M 不再加上第一位的1 ,而是还原为0.xxxxxx 的小数。这样做是为了表示±0 ,以及接近于0 的很小的数字。 -
E 全为1 。这时,如果有效数字M 全为0 ,表示± 无穷大(正负取决于符号位s ) ;如果有效数字M 不全为0 ,表示这个数不是一个数(NaN) 。
浮点数的表示
譬如十进制数
0.75(D) = -0.11(B) = -1.1 * 2^-1
所以符号位2^7-1-1=126
。尾数小数点前的100 0000 0000 0000 0000 0000
,阶码二进制表示为-0.75
规格化的浮点数表示为 1 0111 1110 100 0000 0000 0000 0000 0000
。
因为浮点数本身是近似表达,譬如 0x00000009
还原成了浮点数之后,就变成了 0.000000
。将 0x00000009
拆分,得到第一位符号位M=000 0000 0000 0000 000001001
。由于指数
V=(-1)^0×0.00000000000000000001001×2^(-126)=1.001×2^(-146)
由于