【问题标题】:Is it safe when compare 2 float/double directly in Java?直接在 Java 中比较 2 float/double 是否安全?
【发布时间】:2011-10-10 19:18:23
【问题描述】:

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

a == b
b == c

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

Math.sqrt(b) == Math.sqrt(c)
b / 3 == 10 / 3 //In case b = 10, does it return true?

【问题讨论】:

  • 如果 1.0 + 2.0 != 3.0,不管精度如何,你的电脑都坏了。现在如果 0.1 + 0.2 != 0.3,那就更有意义了。

标签: java android


【解决方案1】:

浮点包装类的比较方法可用于比较两个浮点值。

Float.compare(float1,float2)==0

它将比较每个浮点对象对应的整数位。

【讨论】:

  • 但是为什么呢? float1 == float2 做同样的事情!
【解决方案2】:

一般来说,不,这是不安全的,因为这么多的十进制数不能精确地表示为floatdouble 值。经常陈述的解决方案是测试数字之间的差异是否小于某个“小”值(在数学文献中通常由希腊语“epsilon”字符表示)。

但是 - 你需要小心如何进行测试。例如,如果你写:

if (Math.abs(a - b) < 0.000001) {
    System.err.println("equal");
}

如果ab 应该是“相同的”,那么您正在测试绝对错误。如果你这样做,如果ab 是(比如分别为1,999,999.992,000,000.00。这两个数字之间的差异小于最小可表示值在该比例下 对于 float,但它比我们选择的 epsilon 大得多。

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

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");
}

但这也不是完整的答案,因为它没有考虑某些计算导致错误累积到无法控制的比例的方式。更多详情请查看this Wikipedia link

最重要的是,处理浮点计算中的错误比乍看之下要困难得多。


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

  • 如果结果不是整数,整数除法将被截断
  • 整数加减乘法会溢出。

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

【讨论】:

  • 一个绝对完美的答案!非常感谢!
【解决方案3】:

如果你想要更完整的解释,这里有一个很好的:http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html(不过有点长)

【讨论】:

    【解决方案4】:

    b / 3 != 10 / 3 - 如果 b 是像 b = 10.0f 这样的浮点变量,那么 b / 3 是 3.3333,而 10 / 3 是整数除法,所以等于 3。

    如果b == c,那么Math.sqrt(b) == Math.sqrt(c) - 这是因为 sqrt 函数无论如何都会返回 double。

    一般来说,您不应该比较方程式的双精度/浮点数,因为它们是浮点数,因此您可能会出错。您几乎总是希望将它们与给定的精度进行比较,即:

    b - c &lt; 0.000001

    【讨论】:

    • +1 这里的第一句话绝对是需要理解的重要内容。
    【解决方案5】:

    你确实需要小心一点。

    1.0 + 2.0 == 3.0
    

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

    Math.sqrt(b) == Math.sqrt(c) 
    

    如果 b == c.

    b / 3.0 == 10.0 / 3.0
    

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

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

    如果您要测试受浮点近似约束的计算结果,则应在公差范围内进行相等性测试。

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

    【讨论】:

    • 是的,可能很少见,但是当我在VB.NET中做一个学校分数计算器程序时,1 + 2突然返回2.99999,这使得所有逻辑都变为假。罕见在这里是不可接受的。
    • 因为 1 和 2 是可表示的,很难解释。
    • 实际上,2 来自 10 / 5(恰好是 10 / 5),但不知何故,VB.NET 中的 Double 返回 1.9999999 所以当 + 1 时,它是 2.9999999999999。
    • 虽然谨慎对待浮点的工作方式是明智之举,但您不应该偏执。 10.0/5.0 产生 2.0,在 VB.NET 和基于 IEEE754 浮点的所有其他环境中精确表示。更重要的是1.0+2.0==3.0 在这样的环境中。重要的是要知道你能做什么和不能做什么,以及界限在哪里。
    • 好吧,我不太确定 5,我只是确定 210number 相除的结果(来自其他队友的功能,而不是我),并且在理论上/算法上,它应该是整数(尽管返回类型是双精度)。所以也许问题出在那个函数上。
    【解决方案6】:

    将浮点数/双精度数与其他值进行比较的最安全方法实际上是使用查看它们的差异是否很小。

    例如

    Math.abs(a - b) < EPS
    

    其中 EPS 可以是 0.0000001。

    通过这种方式,您可以确保精度误差不会影响您的结果。

    【讨论】:

    • 是的,如果它不安全,我打算这样做。
    【解决方案7】:

    == 比较对于基本上任何语言的双精度/浮点数都不是特别安全。 epsilon 比较方法(检查两个浮点数之间的差异是否相当小)是您最好的选择。

    为:

    Math.sqrt(b) == Math.sqrt(c)
    

    我不知道你为什么不只比较 b 和 c,但 epsilon 比较也可以在这里工作。

    为:

    b / 3 == 10 / 3
    

    由于 10/3 = 3 因为整数除法,这不一定会给出您正在寻找的结果。您可以使用 10.0 / 3,但我仍然不确定您为什么不只比较 b 和 10(在任何一种情况下都使用 epsilon 比较方法)。

    【讨论】:

    • 这只是一个例子,有时您需要一个返回双精度/浮点值的函数(不是 sqrt)进行比较。
    • 明白了。无论如何,您应该使用 Ionel 在他的回答中演示的比较方法。
    【解决方案8】:

    b 是浮点数,10 是整数,那么如果你将两者与你的这个标准进行比较,那么它会给出 false,因为......

    b = flaot (meance ans 3.33333333333333333333333)
    10 is integer so that make sence.
    

    【讨论】:

    • @Rasel ya 你可以用相同的语言进行比较。
    【解决方案9】:

    在java中你可以比较一个浮点数和另一个浮点数,一个双精度数和另一个双精度数。当它们的精度相等时,你会得到正确的结果

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-15
      • 2014-09-29
      • 2018-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-22
      • 2012-10-29
      相关资源
      最近更新 更多