【问题标题】:Floating point precision and equality in JavaJava中的浮点精度和相等性
【发布时间】:2016-02-23 06:55:35
【问题描述】:

众所周知,浮点数,即使是十进制格式中小数点后固定位数的浮点数,也不能精确表示。所以我有以下程序要测试:

public class Main {
  public static void main(String[] args) {
    System.out.printf("0.1 in single precision is %.50f\n", 0.1f);
    System.out.printf("0.2 in single precision is %.50f\n", 0.2f);
    System.out.printf("0.3 in single precision is %.50f\n", 0.3f);
    System.out.printf("0.1 + 0.2 in single precision is %.50f\n", 0.1f + 0.2f);
    System.out.printf("0.1 + 0.2 == 0.3 is %b in single precision\n", 0.1123f * 0.4f + 0.2f * 0.5f == 0.2f * 0.7f + 0.0123f * 0.4f);

    System.out.println();

    System.out.printf("0.1 in double precision is %.50f\n", 0.1);
    System.out.printf("0.2 in double precision is %.50f\n", 0.2);
    System.out.printf("0.3 in double precision is %.50f\n", 0.3);
    System.out.printf("0.1 + 0.2 in double precision is %.50f\n", 0.1 + 0.2);
    System.out.printf("0.1 + 0.2 == 0.3 is %b in double precision\n", 0.1 + 0.2 == 0.3);
  }
}

输出如下:

0.1 in single precision is 0.10000000149011612000000000000000000000000000000000
0.2 in single precision is 0.20000000298023224000000000000000000000000000000000
0.3 in single precision is 0.30000001192092896000000000000000000000000000000000
0.1 + 0.2 in single precision is 0.30000001192092896000000000000000000000000000000000
0.1 + 0.2 == 0.3 is true in single precision

0.1 in double precision is 0.10000000000000000000000000000000000000000000000000
0.2 in double precision is 0.20000000000000000000000000000000000000000000000000
0.3 in double precision is 0.30000000000000000000000000000000000000000000000000
0.1 + 0.2 in double precision is 0.30000000000000004000000000000000000000000000000000
0.1 + 0.2 == 0.3 is false in double precision

我无法从上述结果中回答两个问题,我正在寻求帮助:

  1. 为什么0.10.20.3 的双重表示看起来准确,而0.1 + 0.2 不准确。
  2. 为什么0.1f + 0.2f == 0.3f 返回true?

【问题讨论】:

标签: java floating-point


【解决方案1】:
  1. 我怀疑System.out.printf 在这里正常工作。在编写 0.1 时获得准确的 double 值的可靠方法是编写 new BigDecimal(0.1).toString()
  2. “为什么 0.1f + 0.2f == 0.3f 返回真?”很大程度上是因为您很幸运:将 0.1 舍入为最接近的浮点表示,将 0.2 舍入为最接近的浮点表示,然后将它们相加即可使您最接近的可表示浮点为 0.3。一般来说,这不是真的,这些值只是碰巧起作用。

【讨论】:

  • 对于问题 (2)。我还怀疑 0.1f + 0.2f == 0.3f return true 是巧合。但是,0.1 + 0.2 == 0.3 返回 false。我无法解释为什么单身是“走运”,但在这种情况下双倍不是。也许是因为在这种情况下 double 的额外有效数字对其不利?
  • 是的,差不多。更多的数字意味着更难找到不同的四舍五入来匹配。
  • 0.1000 的 printf 输出...对于 double 情况是正确的,至少在它与 Double.toString(0.1) 一致的情况下是正确的。它在 17 位有效数字后显示零的原因是 toString 在解析小数点的输出点将明确地返回原始双精度数。所以是的,它对输出字符串进行四舍五入,但它被定义为 be 正确,有关一些信息,请参阅 Double.toString 的 javadoc。
  • @Durandal 正确的是它反映了Double.toString,但我相信OP的目标是提取由0.1表示的double的真实数值。
  • 同意,这可能是他的想法。但这很难成为判断正确性的正当依据。正确性需要根据某种规范来判断,而不是某人的意图或直觉。虽然定义非常迂回,但如果您遵循为 printf 提供的 javadoc 参考,您将到达(经过相当多的跳跃)Double.toString。偷偷地隐藏,但它是指定的。
猜你喜欢
  • 1970-01-01
  • 2011-09-03
  • 1970-01-01
  • 2015-05-17
  • 2013-04-25
  • 1970-01-01
  • 2011-07-12
  • 1970-01-01
相关资源
最近更新 更多