Ruby BigDecimal健全性检查(浮动点newb)

我的理解是正确的,使用Ruby BigDecimal类型(即使具有不同的精度和比例长度)应该准确计算还是应该预测浮点诡计?

我在Rails应用程序中的所有值都是BigDecimal类型,我看到一些错误(它们有不同的小数长度),希望它只是我的方法而不是我的对象类型。

使用浮点运算时有两个常见的陷阱。

第一个问题是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可用的内存。

第二个问题是浮点不能准确表达所有分数。 特别是,它们有小数部分的问题,因为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 

在这种情况下,使用十进制浮点仍会产生舍入误差。

一些结论:

  • 如果你用十进制分数(例如金钱)进行计算,则十进制浮点数很棒。
  • 如果你需要任意精度浮点数,Ruby的BigDecimal也可以正常工作,并且不关心它们是十进制还是二进制浮点数。
  • 如果你使用(科学)数据,你通常会处理固定的精确数字; Ruby的内置浮动可能就足够了。
  • 在任何情况下,你都不能指望任何类型的浮点运算都是精确的。