【问题标题】:Strange floating-point behaviour in a Java program [duplicate]Java程序中奇怪的浮点行为[重复]
【发布时间】:2010-09-24 13:28:02
【问题描述】:

在我的程序中,我有一个包含 25 个双精度值 0.04 的数组 当我尝试在循环中对这些值求和时,我得到以下结果:

0.0 + 0.04 = 0.04
0.04 + 0.04 = 0.08
0.08 + 0.04 = 0.12
0.12 + 0.04 = 0.16
0.16 + 0.04 = 0.2
0.2 + 0.04 = 0.24000000000000002
0.24000000000000002 + 0.04 = 0.28
0.28 + 0.04 = 0.32
0.32 + 0.04 = 0.36
0.36 + 0.04 = 0.39999999999999997
0.39999999999999997 + 0.04 = 0.43999999999999995
0.43999999999999995 + 0.04 = 0.4799999999999999
0.4799999999999999 + 0.04 = 0.5199999999999999
0.5199999999999999 + 0.04 = 0.5599999999999999
0.5599999999999999 + 0.04 = 0.6
0.6 + 0.04 = 0.64
0.64 + 0.04 = 0.68
0.68 + 0.04 = 0.7200000000000001
0.7200000000000001 + 0.04 = 0.7600000000000001
0.7600000000000001 + 0.04 = 0.8000000000000002
0.8000000000000002 + 0.04 = 0.8400000000000002
0.8400000000000002 + 0.04 = 0.8800000000000002
0.8800000000000002 + 0.04 = 0.9200000000000003
0.9200000000000003 + 0.04 = 0.9600000000000003

为什么会发生这种情况?!

【问题讨论】:

标签: java math


【解决方案1】:

您可能希望查看 java BigDecimal 类作为浮点数和双精度数的替代方案。

【讨论】:

    【解决方案2】:

    其他答案提到了原因,但没有提到如何避免。

    有几种解决方案:

    • 缩放:如果所有数字都是 0.01 的倍数(例如),则将所有数字乘以 100 并使用整数算术(精确)。
    • 数字类型:如果您的语言有数字类型(如 SQL 中的 numeric 类型),您可以使用它。
    • 任意精度有理数:使用像 GMP 这样的 bignum 库,它允许您将这些数字表示为两个整数的比率。
    • 十进制浮点数:如果你有一个像IEEE-754r 那样的十进制浮点数,你可以使用它。

    【讨论】:

      【解决方案3】:

      【讨论】:

      • 对于大多数编程语言中浮点表示的新手来说,该文档非常密集。我不会在 CS 教育至少一年(如果不是三年)的人之外推荐它。
      • 我同意。另一方面,对于自学成才的从业者和成绩优异的人来说,如果他们面临数字问题,知道它在哪里是很好的。
      • 这仍然是人们应该知道的事情,即使它太密集以至于他们无法阅读。 ;)
      【解决方案4】:

      编程语言中最常见的浮点值存储 - IEEE singles and doubles - 对大多数小数没有精确的表示。

      原因是它们以二进制浮点格式存储值,而不是十进制浮点格式。唯一可以精确表示的小数值是二的负幂之和。像这样的数字:

      • 0.5 (2^-1)
      • 0.125 (2^-3)
      • 0.625 (2^-1 + 2^-3)

      等等

      您所看到的事实是,像 0.96 这样的数字的表示不能完全表示,因为它们不能表示为 2 的负幂之和。因此,当以小数形式以全精度打印出来时,它们将与原始值不匹配。

      【讨论】:

      • “而不是十进制”有点给出错误的想法。如果它使用十进制,它将被限制为小数值,即十的负幂之和,所以这并不能真正解决很多问题。阅读您的答案的人可能会认为“只要他们使用 base10,问题就会消失”
      • @jalf,没错,但至少十进制浮点表示会令习惯于简单口袋会计的人感到惊讶。加起来一堆 20 镍币,却没有得到一分钱,这让很多人感到惊讶。十进制表示法可以正确处理这种情况,并用小学算术课应该熟悉的数字来解决有趣的问题。
      猜你喜欢
      • 1970-01-01
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多