5

这是我写的一段代码:

#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; 
}

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

4

4 回答 4

11

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

printf ("%.50lf\n", num);

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

1441.14409999999998035491444170475006103515625

现在这实际上是基于您输入的正确(即最接近的)值。从那里开始的下一个最高数字为您提供:

1441.144100000000207728589884936809539794921875

第一个值的错误是:

0.00000000000001964508555829524993896484375
               ^ ~ 2 x 10^-14

而第二个错误是:

0.000000000000207728589884936809539794921875
              ^ ~ 2 x 10^-13

你可以看到后一个错误大约是 10 倍。

当您将其乘以10000并尝试将其硬塞到 中时,它会向下int舍入(截断)。那是因为 (C11) 标准中有这样的说法:6.3.1.4

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

您可以尝试的一件事是将鞋拔线更改为:

tmp = num * 10000 + 0.5;

这有效地将截断转换为舍入操作。我认为这适用于所有情况,但您可能需要对其进行测试(并密切关注)以防万一。

于 2012-11-23T08:38:57.210 回答
1

对于一般原则,paxdiablo 的答案包含相关部分。大多数终止小数不能精确表示为二进制浮点数,因此浮点变量的值比给定字符串中数字表示的数学值稍小或稍大,因此当您想要获得适当的整数时缩放后的值,你应该四舍五入而不是截断。

但是在这里的具体例子中,我们有一个不同的场景。最接近 1441.1441 的 IEEE754 双精度(64 位二进制)值是

1441.14409999999998035491444170475006103515625

这确实比 1441.1441 小一点。但如果将该值乘以 10000 作为 IEEE754 双精度值,则结果正好是

14411441

这里发生的情况是,如 5.2.4.2.2 第 9 段所允许的那样

除了赋值和强制转换(删除所有额外的范围和精度)之外,具有浮动操作数的运算符产生的值和经过通常算术转换的值和浮动常量的值被评估为范围和精度可能大于要求的格式类型

(强调我的),乘积的计算精度比类型(可能是 x87 80 位格式)要求的精度更高,产生的值略小,当乘法的结果转换为int时,小数部分被丢弃,你得到 14411440。

scanf("%lf",&num);

该值存储在 中num,因此它的精度必须为double

tmp=num*10000;

该产品num * 10000既不存储也不转换为double,因此它可能具有更高的精度,从而导致比最接近的值更小或更大的double值。然后截断该值以获得int.

如果您将产品存储在double变量中

num *= 10000;
tmp = num;

double在转换为之前将其转换为int,

tmp = (double)(num * 10000);

您应该得到输入的结果 14411441 1441.1441(但请注意,并非所有编译器在转换或存储时总是遵守转换为所需精度的要求 - 违反标准 - 所以不能保证所有优化设置都会产生 14411441 )。

由于许多 64 位平台使用 SSE 指令而不是 x87 协处理器执行浮点运算,因此观察到的行为不太可能出现在 64 位系统上而不是 32 位系统上。

于 2012-11-23T13:13:31.873 回答
0

试着把它变成这样:

float a = 3.14;

int i = (int)(a+0.5);

在你的情况下:

 double num;
 int tmp;
 printf("enter a number!\n");
 scanf("%lf",&num);
 tmp=(int)(num*10000 + 0.5);
 printf(" temp=%d\n",tmp);
于 2012-11-23T08:43:03.040 回答
-4

看起来 scanf 在 scanf 中使用浮点精度。我简要检查了 1441.1441 在浮点数中表示为 1441.1440。一般来说,您不应该依赖浮点运算的精度。

于 2012-11-23T08:56:06.013 回答