0

据我了解,著名的

 (0.1 + 0.2) !== 0.3

gotcha 实际上不是 Javascript 的错。这正是 IEEE 754 的工作方式。类似的输出发生在 Python 中,它也遵循 IEEE 754 规则。

那么这个特定示例如何在 C 中按预期工作,有时. 如果我做一个直接比较

printf("%d\n", (0.1+0.2) == 0.3);

我得到了(未?)预期的输出0,但是如果我将这些值放入变量中或将它们打印出来,我会得到正确四舍五入的答案。

C 可运行示例

IEEE 754 的 C 实现是否做了额外的事情?还是我完全错过了其他东西。

更新

我发布的代码示例由于拼写错误而损坏。试试这个 Fixed C Runnable Example

但原来的问题仍然存在。

double d1, d2, d3;
d1 = 0.1;    d2 = 0.2;    d3 = d1 + d2;
printf ("%d\n", ((((double)0.1)+((double)0.2)) == ((double)d3)));
printf ("%.17f\n", d1+d2);
printf ("%d\n", ((d1+d2) == d3));

输出是

1
0.30000000000000004
1

现在改写的问题是:

  1. 为什么(以及何时以及如何)C 编译器冒昧地说

    0.3 == 0.30000000000000004

  2. 鉴于所有事实,C 实现不是真的坏了,而不是 Javascripts'?

4

3 回答 3

4

为什么(以及何时以及如何)C 编译器冒昧地说

    0.3 == 0.30000000000000004

鉴于所有事实,C 实现不是真的坏了,而不是 Javascripts'?

它不是。

给出的输出来自以下代码:

printf ("%d\n", ((((double)0.1)+((double)0.2)) == ((double)d3)));

但你写道:

d1 = 0.1;    d2 = 0.2;    d3 = d1 + d2;

所以d3不是,而是 0.30.30000000000000004

于 2012-07-03T10:04:37.737 回答
1
`printf("%d\n", (0.1+0.2) == 0.3);`

这些是 DOUBLEs 而不是 FLOATs。

做:

printf("%d\n", (0.1+0.2) == 0.3);
printf("%d\n", (0.1f+0.2f) == 0.3f);

瞧!

http://codepad.org/VF9svjxY

Output:
0
1

看看这个问题。这是关于其他的,但是使用 GCC 的 ppl 得到的结果与使用 MSVC 的 ppl 不同。 打印浮点数的整数部分

于 2012-07-03T09:58:21.510 回答
0

您的示例代码使用 1、2 和 (1+2),它们都可以用双精度浮点数精确表示。另一方面,0.1 不能完全用浮点数表示,因此你得到了这个数字的近似值。将大约 0.1 添加到大约 0.2 时,您将得到大约 0.3,但这是否与编译器在表示 0.3 时选择的近似值完全相同,谁知道呢。

表示使用二进制。这意味着它使用 1/2, 1/4, 1/8, 1/16, 1/32 (等等到一些精度......)。这意味着可以准确地表示 0.5、0.25 等。不是二进制分数的精确和的数字可以非常接近地近似。

解决方案:不要相互比较浮点数。将它们的差异与您不关心的一些小数字进行比较。

#define EPSILON 0.000001
printf("%d", fabs((0.1+0.2) - 0.3 ) < EPSILON );

我不确定为什么 C 代码有效而 python/javascript 无效。这是魔法。但希望无论如何这都能回答你的问题。

于 2012-07-03T09:53:30.890 回答