C语言

浮点数陷阱

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标准中,规格化的浮点数真值表示为:
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 ,程序会一直执行下去。

参考

IEEE754浮点数的表示方法

上一篇下一篇

猜你喜欢

热点阅读