我的理解是正确的,使用Ruby BigDecimal
类型(即使具有不同的精度和比例长度)应该准确计算还是应该预测浮点诡计?
我在Rails应用程序中的所有值都是BigDecimal
类型,我看到一些错误(它们有不同的小数长度),希望它只是我的方法而不是我的对象类型。
答案 0 :(得分:33)
使用浮点运算时有两个常见的陷阱。
第一个问题是Ruby浮点具有固定的精度。在实践中,这将是1)对你没有问题或2)灾难性的,或3)介于两者之间的东西。请考虑以下事项:
# float
1.0e+25 - 9999999999999999900000000.0
#=> 0.0
# bigdecimal
BigDecimal("1.0e+25") - BigDecimal("9999999999999999900000000.0")
#=> 100000000
精度差1亿!非常认真,对吧?
除了精度误差仅为原始数的0.000000000000001%。你真的应该决定这是不是一个问题。但是使用BigDecimal
可以解决问题,因为它具有任意精度。您唯一的限制是Ruby可用的内存。
第二个问题是浮点无法准确表达所有分数。特别是,它们存在 decimal 分数的问题,因为Ruby(以及大多数其他语言)中的浮点数是二进制浮点数。例如,小数部分0.2
是永久重复的二进制分数(0.001100110011...
)。无论精度如何,都无法准确地将其存储在二进制浮点中。
当你对数字进行四舍五入时,这会产生很大的不同。考虑:
# float
(0.29 * 50).round
#=> 14 # not correct
# bigdecimal
(BigDecimal("0.29") * 50).round
#=> 15 # correct
BigDecimal
可以精确地描述十进制分数。但是,有一些分数无法用小数部分精确描述。例如,1/9
是一个永久重复的小数部分(0.1111111111111...
)。
同样,当你围绕一个数字时,这会咬你。考虑:
# bigdecimal
(BigDecimal("1") / 9 * 9 / 2).round
#=> 0 # not correct
在这种情况下,使用十进制浮点数仍然会产生舍入错误。
一些结论:
BigDecimal
也可以正常工作,并且不关心它们是十进制还是二进制浮点。