1

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でしょうか?

4

1 に答える 1

5

AFAICS ruby​​ round() は正しく動作します。いずれにせよ、これは libm の round() 関数の単なるラッパーにすぎないと思われます。

その理由は、浮動小数点リテラルをバイナリで正確に表現できないためです。たとえば、"1.015" をさらにいくつかの小数で表示すると、"1.0149999999999999" となります。したがって、10 進数 2 桁に丸める場合、1.01 は 1.02 よりも真の値に近くなります。他の例についても同様です。

また、IEEE 754 のデフォルトの丸めモードは、学校でよく知られている「最も近いものに丸め、0 から離れて結合する」とは異なる「最も近いものに丸め、偶数に結合する」であることにも注意してください。

于 2012-09-17T09:10:48.117 に答える