logo

相等,还是不等(1) - 0.1 + 0.2 = 0.30000000000000004

入门。

比较两个数, 用 ==

jshell> 1 + 1 == 2
$1 ==> true

jshell> 1 + 1 + 1 == 3
$2 ==> true

放弃?

到了小数好像就不太对了:

jshell> 0.1 == 0.1
$3 ==> true

jshell> 0.1 + 0.1 == 0.2
$1 ==> true

jshell> 0.1 + 0.1 + 0.1 == 0.3
$2 ==> false

是 Java 的 bug?Python 好像也一样:

>>> 0.1 + 0.1 == 0.2
True
>>> 0.1 + 0.1 + 0.1 == 0.3
False

其他一些例子: 2.0 - 1.1 应该是 0.9,对吗?

>>> 2.0 - 1.1
0.8999999999999999

1.0 / 0.1 == 10, 所以 1.0 % 0.1 应该是 0,对吗?

>>> 1.0 % 0.1
0.09999999999999995

进阶!

计算机世界的 0.1 并不是真正的 0.1,而是比 0.1 稍大一点点。我们多打印出来几位小数看看:

>>> '%.60f' % 0.1
'0.100000000000000005551115123125782702118158340454101562500000'

所以 1.0/0.1 并不是 10,而是只够 9 个"0.1",剩下了 0.09999999999999995

正因为浮点数这种特性,在高精度计算,或涉及到钱的时候,不能直接使用浮点数。

解决方案:

  1. 把浮点数转换为整数,比如把金额乘以 100,然后当成整数进行计算,只是单位变成了“分”而不是“元”
  2. 用特殊的类,比如 Java 的 BigDecimal 或 Python 的 Decimal

Python:

>>> from decimal import Decimal
>>> Decimal(1.0) % Decimal(0.1)
Decimal('0.09999999999999995003996389187')

>>> Decimal('1.0') % Decimal('0.1')
Decimal('0.0')

>>> Decimal('2.0') - Decimal('1.1')
Decimal('0.9')

Java:

jshell> new BigDecimal("2.00").subtract(new BigDecimal("1.10"))
$1 ==> 0.90

由于 0.1+0.2=0.30000000000000004,有一个专门的网站讨论这个问题:https://0.30000000000000004.com/