在Java中直接比较2 float/double是否安全?

Luk*_* Vo 4 java android

如果我使用这样的比较是安全的(a是int,b和c是float/double):

a == b
b == c
Run Code Online (Sandbox Code Playgroud)

它可能听起来很荒谬,但在我的旧编程语言中,有时1 + 2 == 3是假的(因为左侧返回2.99999999999 ......).那么,这个:

Math.sqrt(b) == Math.sqrt(c)
b / 3 == 10 / 3 //In case b = 10, does it return true?
Run Code Online (Sandbox Code Playgroud)

Ste*_*n C 12

一般而言,由于无法精确表示如此多的十进制数floatdouble值,因此不安全.如果数字之间的差异小于某个"小"值(通常用数学文献中的希腊'epsilon'字符表示),则经常说明的解决方案是测试.

但是 - 你需要小心谨慎地进行测试.例如,如果你写:

if (Math.abs(a - b) < 0.000001) {
    System.err.println("equal");
}
Run Code Online (Sandbox Code Playgroud)

在哪里ab应该是"相同",你正在测试绝对错误.如果你这样做,你可以进入,如果麻烦ab是(say_ 1,999,999.992,000,000.00分别.这两个数字之间的差异小于最小表示值在这种规模float,但它是比我们的选择小量大得多.

可以说,更好的方法是使用相对误差 ; 例如编码(防御性地)为

if (a == b ||
    Math.abs(a - b) / Math.max(Math.abs(a), Math.abs(b)) < 0.000001) {
    System.err.println("close enough to be equal");
}
Run Code Online (Sandbox Code Playgroud)

但即使这不是完整的答案,因为它没有考虑某些计算导致错误累积到无法管理的比例的方式.请查看此Wikipedia链接以获取更多详细信息.

最重要的是,处理浮点计算中的错误比初看起来要困难得多.


另一点需要注意的是(正如其他人所解释的)整数算法在几个方面与浮点算法的行为非常不同:

  • 如果结果不是整数,则整数除法将截断
  • 整数加法减法和乘法将溢出.

无论是在编译时还是在运行时,这两种情况都没有任何警告.


Dav*_*nan 5

你需要做一些照顾.

1.0 + 2.0 == 3.0
Run Code Online (Sandbox Code Playgroud)

是真的,因为整数是完全可表示的.

Math.sqrt(b) == Math.sqrt(c) 
Run Code Online (Sandbox Code Playgroud)

如果b == c.

b / 3.0 == 10.0 / 3.0
Run Code Online (Sandbox Code Playgroud)

如果b == 10.0这就是我认为你的意思.

最后两个示例比较了同一计算的两个不同实例.当您使用不可表示的数字进行不同的计算时,则完全相等测试失败.

如果您正在测试受浮点近似计算的结果,则应进行相等测试,直至达到公差.

你有任何具体的现实世界的例子吗?我想你会发现很少想用浮点测试相等性.