Java程序中奇怪的浮点行为

在我的程序中,我有一个具有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 

为什么地球上会发生这种事?

编程语言中浮点值最常见的存储单位是IEEE单数和双精度单元 ,对大多数小数不具有精确的表示forms。

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

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

等等。

你所看到的是这样一个事实:像0.96这样的数字的表示是不完全可表示的,因为它们不能表示为两个负的幂的和。 因此,当以十进制小数完全精确打印出来时,它们将不匹配原始值。

另请参阅“ 每位计算机科学家应了解的浮点数 ”

其他答案提到了为什么,但不是如何避免它。

有几个解决scheme:

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

你可能希望看看java BigDecimal类作为float和double的替代。