【问题标题】:surprising double comparison [duplicate]令人惊讶的双重比较[重复]
【发布时间】:2014-02-16 15:41:24
【问题描述】:

我弄乱了代码执行结果。

代码:

System.out.println(0.2==0.1+0.1);
System.out.println(0.3==0.1+0.1+0.1);

输出:

true
false

我知道 0.2 和 0.3 不能正确转换为二进制。

为什么我会看到不同的结果?

更新:

我可以在没有编译器的情况下预测类似问题的结果吗?

【问题讨论】:

  • 我不懂javascript
  • 查看0.6==0.1+0.1+0.1+0.1+0.1+0.1。这是真的。
  • herohuyongtao - 请解释一下为什么是真的?
  • @gstackoverflow 在你的编译器上测试。
  • 请阅读@nr4bt 发布的link。这是每个程序员都应该了解的复杂话题。

标签: java primitive


【解决方案1】:
System.out.println(0.1+0.1+0.1);

输出

0.30000000000000004

浮点运算存在舍入误差。有些值不能以基数 2 表示,你不能依赖比较浮点数。 base-2 中的 0.1 相当于 base-10 中的 1/3。

你可以看到下面的链接

What Every Computer Scientist Should Know About Floating-Point Arithmetic

【讨论】:

  • 我正要加一条评论说这可能就是它了。
  • 为什么0.1+0.1 没问题?
  • 每次使用浮点数执行额外计算时,答案中的错误会越来越多。当您仅添加 2 个浮点数时,错误还不足以考虑!=.
  • @Takendarkk 我买不到。查看0.4==0.1+0.1+0.1+0.1,这是真的。
  • @herohuyongtao 有趣。这绝对是不是我所期待的。我正在调查。
【解决方案2】:

您看到的事实是浮点值不是很准确,您不应该使用== 运算符来比较它们。对于比较,您应该使用 epsilon 比较,即。对于两个浮点值 f1 和 f2

if  (Math.abs(f1 - f2) < EPSILON ) {
   // they are equal
}

EPSILON 是一个非常小的浮点值

【讨论】:

  • ... EPSILON 是一个非常小的浮点值反映了比较中必要的精度,但不小于这个
【解决方案3】:

PHP 给出了这个:

<?php

printf("%0.20f\n", 0.1+0.1);
printf("%0.20f\n", 0.1+0.1+0.1);

?>
0.20000000000000001110
0.30000000000000004441

<?php
  echo 0.2==0.1+0.1?"true\n":"false\n";
  echo 0.3==0.1+0.1+0.1?"true\n":"false\n";
?>
true
false

第一个为“真”的原因:

<?php
   printf("%0.20f\n", 0.1+0.1);
   printf("%0.20f\n", 0.1+0.1+0.1);
   echo "\n";
   printf("%0.20f\n", 0.2);
   printf("%0.20f\n", 0.3);
?>

输出

0.20000000000000001110
0.30000000000000004441

0.20000000000000001110
0.29999999999999998890

【讨论】:

  • nr4bt 解释了为什么 System.out.println(0.3==0.1+0.1+0.1) 返回 false。但我还没有回答为什么 System.out.println(0.2==0.1+0.1) 返回 true
  • 根据你的结果——非常非常奇怪
  • 关于你的更新:我可以在没有编译器的情况下预测结果吗?
  • 不,它具有浮点值的性质,无论您使用哪种语言,结果在某种程度上都是不可预测的。您可以设置一个比较例程,将指数和尾数分别作为整数进行比较,或者您使用@marcin_j 的解决方案
  • 它是 Double - 不是浮动
【解决方案4】:

您不能依靠== 来很好地处理float 数字,因为它们无法在计算机上准确表示,因此其结果不可靠。如果要检查两个float 数字是否相等,请改用fabs(a-b) &lt; epsilon

附:以下测试在C++ 下进行,结果令人惊讶(只是为了好玩,以表明它是多么不可靠):

cout << (0.1==0.1) << endl;                                // true
cout << (0.2==0.1+0.1) << endl;                            // true
cout << (0.3==0.1+0.1+0.1) << endl;                        // false
cout << (0.4==0.1+0.1+0.1+0.1) << endl;                    // true
cout << (0.5==0.1+0.1+0.1+0.1+0.1) << endl;                // true
cout << (0.6==0.1+0.1+0.1+0.1+0.1+0.1) << endl;            // true
cout << (0.7==0.1+0.1+0.1+0.1+0.1+0.1+0.1) << endl;        // true        
cout << (0.8==0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1) << endl;    // false

【讨论】:

    猜你喜欢
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 2019-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多