浮点不准确

时间:2013-04-02 01:37:13

标签: c floating-point type-conversion rounding

混合int和double会在以下程序中产生奇怪的结果:

int main()
{
    double x = 9.90, y = 10.0, z, w;
    int    ip, fp;

    z = y - x;

    ip = (int) z;

    w = (z - ip)*100;

    printf( "\nx = %f\ty = %f\tz = %f\tw = %f\n",
            x, y, z, w );

    printf("\nip = %d", ip); /* So far, so good */

    fp = (int) w; /* Why does fp get 9 and not 10??? */

    printf("\nfp = %d\n", fp);

    return 0;
}

结果:

x = 9.900000    y = 10.000000   z = 0.100000    w = 10.000000

ip = 0
fp = 9 (Should be 10!)

使用MingGW(WinXP)e Clang(MacOSX)的结果是相同的。有人能解释这种奇怪的行为吗?

2 个答案:

答案 0 :(得分:1)

问题在于你实际上是在尝试w = 0.1 * 100,并且值不能用浮点精确表示(与1/3无法精确表示的方式相同十进制)。

你得到的二进制0.1是这样的:

0.00011001100110011001100110011001100110011001100110011001...

最后4位数字永远重复。

虽然double没有无限的位数,所以它实际上是:

1.100110011001100110011001100110011001100110011001100110 * 2**(-4)

其中数字因不适合而被丢弃,从“01001001 ...”开始。因为丢弃的数字以0开头,所以数字将向下舍入。这意味着您实际上最终会执行w = 0.9999999999 * 100

之类的操作

答案 1 :(得分:0)

错误的发生是因为double无法完全保留值9.9。它可以管理的最接近的是9.9000000000000003552713678800500929355621337890625。因此,w的值不是10,而是9.99999999999996447286321199499070644378662109375

当您对printf使用%f时,它会将您的值四舍五入到6位数。如果您将printf格式更改为%.60f,则可以看到值的完整精度。