?
IEEE浮点数标准定义了两种基本的格式:以4个字节表示单精度格式和8个字节表示双精度。
?
1. 存储规则
float:
1位符号数 8位指数 23位有效数
0/1 bias:127
double:
1位符号数 11位指数 52位有效数
0/1 bias:1023?
?
2. 浮点数存储分析
(8.25)10 = (1000.01)2
?
符号位: 0 0正数,1负数
指数位: 10000010 科学记数法表示:1.00001*2^3,指数为:127+3=130
有效位: 00001000000000000000000 最高位1去除,不足23位则补0
8.25储存方式为:01000001000001000000000000000000
?
反向推导01000001000001000000000000000000对应十进制值:
0 正数
10000010 130-127=3有效位为3
00001000000000000000000 整数部分补1为:1000 小数部分01 即1000.01
?
下面来点复杂的,求8.58单精度浮点数存储方式:
十进制小数转化为二进制,不断乘以2,顺次取整数位。
0.58*2 = 1.16 1?
0.16*2 = 0.32 0
0.32*2 = 0.64 0
0.64*2 = 1.28 1
0.28*2 = 0.56 0
0.56*2 = 1.12 1
0.12*2 = 0.24 0
0.24*2 = 0.48 0
0.48*2 = 0.96 0
0.96*2 = 1.92 1
0.92*2 = 1.84 1
0.84*2 = 1.68 1
0.68*2 = 1.36 1
0.36*2 = 0.72 0
0.72*2 = 1.44 1
0.44*2 = 0.88 0
0.88*2 = 1.76 1
0.76*2 = 1.52 1
0.52*2 = 1.04 1
0.04*2 = 0.08 0
0.08*2 = 0.16 0
0.16*2 = 0.32 0
0.32*2 = 0.64 0
0.64*2 = 1.28 1
0.28*2 = 0.54 0
0.54*2 = 1.08 1
通过上面的计算,我们发现0.58自0.16处一直循环,二进制方式不能完整表示该整数,这会有什么影响?
?
8.58 = 1000.10010100011110101110000...
二进制存储方式:
0 10000010 00010010100011110101110
?
测试程序:
class="shell">float a = 8.58f; char *p = (char*)&a; p a $1 = 8.57999992 p /x *p@4 $2 = {0xae, 0x47, 0x9, 0x41}
?
gdb调试发现a的值怎么变成8.57999992,我们用上述二进制计算其10进制看看:
0.58 = 10010100011110101110000
?
>>> 2**-1+2**-4+2**-6+2**-10+2**-11+2**-12+2**-13+2**-15+2**-17+2**-18+2**-19 0.57999992370605469
?
上述结果与gdb调试一致,除了可以表示为2的幂次以及整数数乘的浮点数可以准确表示外,其余的数的值都是近似值。同时float有效位才23位,导致大部分位数被截断。
?
3. 浮点数大小比较
既然浮点数大多是存储的近似值,那么如何比较其大小?
/** * 浮点数大小比较 */ bool IsEqual(float a, float b, float absError, float relError ) { // 2的幂次小数,如0.5 if (a==b) return true; // 绝对误差判断 if ( fabs(a-b)<absError ) return true; // 相对误差判断 if ( fabs(a)<fabs(b) ) return (fabs((a-b)/b)<relError ) ? true : false; else return (fabs((a-b)/a)<relError ) ? true : false; }
?
?
4. 硬件支持
为了加快浮点数的运算速度,现处理器大多增加了FPU(Floating-point Unit),用于处理浮点数运算。
可以看下VC++6.0的启动函数:
main() mainCRTStartUp() _cinit(); // 初始化全局数据和浮点寄存器 mainret = main( _argc, _argv, _environ ); // 调用main
?
_cinit函数片断:
// 初始化寄存器 if( _FPinit != NULL ) (*_FPinit)();
?
参考链接:
http://www.cnblogs.com/xkfz007/articles/2590472.html
https://www.cnblogs.com/dolphin0520/archive/2011/10/02/2198280.html
?
?
?
?
?