惊人的双重比较

时间:2014-01-25 16:29:14

标签: java primitive

我搞乱了代码执行结果。

代码:

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无法转换为二进制校正。

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

更新

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

4 个答案:

答案 0 :(得分:9)

System.out.println(0.1+0.1+0.1);

输出

0.30000000000000004

浮点算术有一个舍入误差。有些值无法在基数2中表示,您不能依赖于比较浮点数。基础-2中的0.1与基础-10中的1/3相似。

您可以看到以下链接

What Every Computer Scientist Should Know About Floating-Point Arithmetic

答案 1 :(得分:2)

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

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

EPSILON是一个非常小的浮点值

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您不能依赖==才能正常使用float个数字,这些数字的结果不可靠,因为它们无法在计算机上准确表示。如果您想检查两个float数字是否相等,请改用fabs(a-b) < epsilon

P.S。以下测试位于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