【发布时间】:2018-08-07 10:41:37
【问题描述】:
我刚刚在 TDD 期间遇到了一个有趣的案例:
Failure/Error: expect(MoneyManager::CustomsCalculator.call(price: 31, weight: 1.12)).to eq 9.3
expected: 9.3
got: 0.93e1
我进一步调查发现:
require 'bigdecimal'
=> true
2.4.2 :005 > require 'bigdecimal/util'
=> true
...
2.4.2 :008 > 1 == 1.to_d
=> true
2.4.2 :009 > 2 == 2.to_d
=> true
2.4.2 :010 > 2.0 == 2.0.to_d
=> true
2.4.2 :011 > 1.3 == 1.3.to_d
=> true
2.4.2 :012 > 9.3 == 9.3.to_d
=> false
为什么是9.3 == 9.3.to_d false?
PS,我很清楚 Float 和 BigDecimal 是什么,但我对这种特殊行为感到非常困惑。
【问题讨论】:
-
你不应该对浮点值进行相等性测试。您总是需要处理浮点数不准确的内部表示问题,因此 == 和 != 并不是非常有用。如果您检查差异
1.3.to_d - 1.3,您会发现它不完全是 0 -
如修补程序所述。
(f1 - f2).abs < EPSILON是比较浮点数的传统方式。使用平等只会让人流泪。这种方法对运行代码的机器也更好。 -
这种行为也不仅仅适用于
bigdecimal。我与 Ruby 和打包字符串进行了很多互操作。[0.123].pack('f').unpack('f') #=> 0.12300000339746475使用==是毫无价值的。但如果使用精度为 7 位0.0000001的 epsilon 值,则结果符合预期。 -
9.3 == 9.3.to_d.to_f #=> true???? -
也许这是关于 BigDecimal 的默认精度
Float::DIG(即15)的一个错误:9.3 == 9.3.to_d(15) #=> false与9.3 == 9.3.to_d(16) #=> true
标签: ruby floating-point decimal precision