剖析浮点数
[转载]http://blog.csdn.net/masefee/archive/2010/01/30/5272554.aspx
这里历史和发展就不说了,直接从IEEE浮点标准说起。
在 IEEE 标准中,浮点数是将特定长度的连续字节的所有二进制位分割为特定宽度的符号域,指数域和尾数域三个域,其中保存的值分别用于表示给定二进制浮点数中的符号,指数和尾数。这样,通过尾数和可以调节的指数(所以称为"浮点")就可以表达给定的数值了。
具体的格式:
还原:
这里因为之前我们都知道有个固定的1给省略了,因此这里要给加上去。加上去之后:
1 010 0110 0110 0110 0110 011 0
这里是24位,我们先不管,小数点添进去:
1 . 010 0110 0110 0110 0110 011 0 * 2^2
然后将科学计数法变换成普通的二进制小数:
1 01 . 0 0110 0110 0110 0110 011 0
到这里,就真正可以把整数部分换成十进制了:
1 01 . 0 0110 0110 0110 0110 011 0
5. xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
我们知道了,整数部分是5,后面的小数部分再进行逆运算:
0 . 0 0110 0110 0110 0110 011 0 =
0 + 0*2^-1 + 0*2^-2 + 1*2^-3 + 1*2^-4 + 0*2^-5 + 0*2^-6 + 1*2^-7 + ... ... + 0*2^-21 这样一个式子,我们算出结果来,放在浮点数里:
5.1999998。
因此我们可以看到精度已经有损失了。
64位浮点数 的换算:
这里就不再具体说明怎么换算的了,只需要提到2个地方:
一是,中间的阶码在double中占有11位,因此阶码就不是+127了,而是加上1023,因为11位能表示的最大无符号数是2047,因此有符号范围[-1024, 1023]。
二是,尾数是52位,因此精度更高,能表示的数也就越大。我们在换算5.2的时候,后面的小数二进制+前面的5的二进制再省略一位后的总位数要填满52位。
给出一段验证代码:
#include <stdio.h>#include <string.h>int main(){ union { float f; int i; }u; u.f = 5.2f; printf("%.7f\n", u.f); //5.1999998一旦放入,精度已经发生了变化 printf("%x\n", u.i); union { float f; int i; }v; v.i = 0x40A66666; printf("%.7f\n", v.f); printf("%x\n", v.i); return 0;}