Ruby Float#round方法与round(2)表现不正确

时间:2012-09-17 08:32:42

标签: ruby floating-point floating-accuracy ruby-1.9.3

我了解到建议使用BigDecimal代替Float,但这个要么是错误,要么强调Float的深奥性质。似乎Float#round(2)在“1.015”,“1.025”和“1.035”方面存在问题。

1.015.round(2)
 => 1.01    # => WRONG .. should be 1.02
1.025.round(2)
 => 1.02    # => WRONG .. should be 1.03
1.035.round(2)
 => 1.03    # => WRONG .. should be 1.04
1.045.round(2)
 => 1.05    # => CORRECT
1.016.round(2)
 => 1.02    # => CORRECT

round(3)效果很好。

1.0015.round(3)
 => 1.002  # => CORRECT
1.235.round(2)
 => 1.24   # => CORRECT 

要在Rails应用程序中修补此问题,我这样做了:

config/initializers/float_mp.rb

require 'bigdecimal'

class Float
  def round(val=0)
     BigDecimal.new(self.to_s).round(val).to_f
  end
end

这似乎是一种奇怪且昂贵的解决方法。这可能是Float#round中的错误吗?

1 个答案:

答案 0 :(得分:5)

AFAICS ruby​​ round()正常工作。据推测,它只是libm中round()函数的包装器。

所以原因是你的浮点文字不能用二进制表示。例如。打印带有更多小数的“1.015”给出“1.0149999999999999”;因此,当舍入到两个十进制数字时,1.01更接近真实值而不是1.02。等等你的其他例子。

另请注意,默认的IEEE 754舍入模式是“Round to nearest,ties to even”,这与“Round to nearest to ties from zero”不同,这是您从学校可能熟悉的