首先说下小数的二进制表示。比如3.8,整数部分通过依次除2来解决,结果是11,小数部分通过依次乘2来解决,结果是0.1100 1100 1100… 1100… …无限循环,这就是计算机不能精确表示所有的小数的原因,因此一般有个精度值。
拿3.8举例说一下单精度和双精度下的二进制存储形式。
Float a = 3.8;
Float型占四个字节,4×8 = 32位,从左至右是31~0。31位是符号位,0表示正数,1表示负数,接着30~23位(共8位)表示指数,22~0位(共23位)表示尾数。奇怪,怎么还有指数呢?原来是按科学计数法表示的,当然是二进制下的了。
先把3.8换成二进制下的,
3.8 = 11.1100 1100 1100 1100 … 1100…
科学计数法表示:3.8 = 1. 1 1100 1100 1100 … 1100 … × 2^1。
按二进制下的科学计数法表示后,会发现一个特点,前面的非幂形式的数的整数部分永远是1,因此只需记录小数部分就行了,也就是尾数,还有就是2的指数部分。这样3.8在二进制科学计数法的表现形式下,指数是1,尾数是1 1100 1100 1100 1100 … 1100…。
还要注意的是指数部分是有个偏移的,30~23位(共8位)表示指数的,范围是-127~128,因此偏移127(+127),这样0000 0000 表示-127,1111 1111 表示128。其实就是无符号数减去127。指数为1应该表示为1 + 127 = 128 = 1000 0000。
小数部分只能表示23位,因此得截断了,截断后是:1 1100 1100 1100 1100 1100 11
因此3.8单精度表示是0 1000 000 1 1100 1100 1100 1100 1100 11
每8位空一格表示是 0100000 01110011 00110011 00110011
接下来看看双精度double d = 3.8;
Double 型占八个字节,共64位,从左至右是63~0。63位是符号位,0表示正数,1表示负数,接着62~52位(共11位)表示指数,51~0位(共52位)表示尾数。
Double 型62~52位(共11位)表示指数的,范围是-1023 ~ 1024, 因此偏移1023(+1023),这样指数1应该表示为1+1023 = 1024 = 100 0000 0000。
尾数截断至52位,是:1110 01100110 01100110 01100110 01100110 01100110 01100110
3.8的双精度表示如下:
0 10000000000 1110 01100110 01100110 01100110 01100110 01100110 01100110
每8位空一格表示是
01000000 00001110 01100110 01100110 01100110 01100110 01100110 01100110
下表是个总结:
精度型 | S(符号) | P(指数) | M(尾数) | 指数偏移 |
Float | 1 | 8 | 23 | 127 |
Double | 1 | 11 | 52 | 1023 |