C中的数字精度错误

Ron*_*sch 5 c precision floating-point-precision

这是我写的代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    double num;
    int tmp;
    printf("enter a number!\n");
    scanf("%lf",&num);
    tmp=num*10000;
    printf(" temp=%d\n",tmp);

    return 0; 
}
Run Code Online (Sandbox Code Playgroud)

当我输入数字1441.1441时,我得到的结果是14411440而不是14411441,这显然是将我的输入数字乘以10000后的正确结果.有人可以帮我解决这个问题吗?

pax*_*blo 10

由于绝大多数实数实际上无法准确表示,因此您可能会发现它1441.1441实际上存储为类似的东西1441.14409999_blah_blah_blah.您可以通过插入来找到:

printf ("%.50lf\n", num);
Run Code Online (Sandbox Code Playgroud)

scanf看到之后立即(删除尾随零):

1441.14409999999998035491444170475006103515625
Run Code Online (Sandbox Code Playgroud)

现在,这实际上是基于您的输入的正确(即最接近)值.那里的下一个最高数字给你:

1441.144100000000207728589884936809539794921875
Run Code Online (Sandbox Code Playgroud)

第一个值的错误是:

0.00000000000001964508555829524993896484375
               ^ ~ 2 x 10^-14
Run Code Online (Sandbox Code Playgroud)

而第二个错误是:

0.000000000000207728589884936809539794921875
              ^ ~ 2 x 10^-13
Run Code Online (Sandbox Code Playgroud)

你可以看到后者的错误大约是后者的10倍.

当你将它乘以10000并尝试将其变为a时int,它会向下舍入(截断).这是因为(C11)标准有这样的说法6.3.1.4:

当实数浮动类型的有限值被转换为除_Bool之外的整数类型时,小数部分被丢弃(即,该值被截断为零).

你可以尝试的一件事是将你的鞋带线改为:

tmp = num * 10000 + 0.5;
Run Code Online (Sandbox Code Playgroud)

这有效地将截断转换为舍入操作.我认为这适用于所有情况,但你可能想测试它(并密切关注它)以防万一.

  • @Mohamed KALLEL:无论用什么方法"输入"它,都无法准确表示无法准确表示的数字. (7认同)
  • +1,如果你有几个小时,我强烈建议阅读[本文件](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html),它解释了你想知道的一切,以及你没有解决的很多关于浮动指针表示的内容. (3认同)