浮点数陷阱
2017-12-06 本文已影响27人
337b94dc718f
演示代码
#include<stdio.h>
int main () {
double i;
for (i = 0; i != 1; i += 0.1) {
printf ("%lf\n", i);
}
return 0;
}
大家可以先猜想下结果。
结果
打印结果.jpg倒数第三行可以看到我强制退出了程序,否则会一直打印。为什么这样呢?0.1累加十次之后,不应该是1.0吗?
原因
1、浮点数表示方法
根本原因是不清楚浮点数的表示方法。
- 二进制格式
先来说下浮点数的二进制格式,单精度浮点数采用32位bits表示,双精度浮点数采用64位bits表示。分为三部分,符号位(S)、阶码(E)和尾数(M)。
single precision:1位符号位,8位阶码,23位尾数
double precision:1位符号位,11位阶码,32位尾数
符号位1表示负数,0表示正数。
- IEEE754
IEEE754标准中,规格化的浮点数真值表示为:
x =(−1)s * (1.M) *2e
其中E = [e]移码 - 1,阶码的移码即把补码标志位取反,为了能表示正负无穷大。由于尾数高位恒为1,所以只存储浮点数位M。
- 举个栗子
给出十进制数-4.25的机器码,使用单精度
-4.25 = [-100.01]2,符号位为1,尾数为 1.0001,指数为2,
所以尾数域二进制码
M = [000 1000 0000 0000 0000 0000]2
阶码
E = [2]移码 - 1 = [1000 0010]2 - 1 = [1000 0001]
得到机器码为
-4.5 = [1100 0000 1000 1000 0000 0000 0000 0000]2
结论
浮点数不能精确表示某些十进制数,只能取无限近似值。将累加值换为0.5,则程序只打印两次值。
示例代码中的0.1的累加,则是其近似值的累加,所以不会命中 1 ,程序会一直执行下去。