21

Ruby の型 (精度やスケールの長さが異なっていても) を正確に計算する必要があるという私の理解は正しいBigDecimalですか?

Rails アプリケーション内のすべての値はBigDecimal型であり、いくつかのエラーが表示されます (10 進数の長さが異なります)。これがオブジェクト型ではなくメソッドであることを願っています。

4

1 に答える 1

37

浮動小数点演算を扱う場合、よくある落とし穴が 2 つあります。

最初の問題は、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 で使用できるメモリです。

2 つ目の問題は、浮動小数点がすべての分数を正確に表現できないことです。特に、Ruby (および他のほとんどの言語) の浮動小数点数は2 進浮動小数点であるため、小数に関して問題があります。たとえば、小数は永遠に繰り返される 2 進数の分数です ( )。これは、精度に関係なく、2 進浮動小数点に正確に格納することはできません。0.20.001100110011...

これは、数値を丸めるときに大きな違いを生む可能性があります。検討:

# float
(0.29 * 50).round
#=> 14  # not correct

# bigdecimal
(BigDecimal("0.29") * 50).round
#=> 15  # correct

ABigDecimal小数を正確に表すことができます。ただし、小数でも正確に記述できない分数があります。たとえば1/9、永遠に繰り返される小数 ( 0.1111111111111...) です。

繰り返しますが、これは数値を四捨五入するときに噛みつきます。検討:

# bigdecimal
(BigDecimal("1") / 9 * 9 / 2).round
#=> 0  # not correct

この場合、10 進浮動小数点を使用すると、丸め誤差が発生します

いくつかの結論:

  • 小数(たとえば、お金)で計算を行う場合、小数浮動小数点数は素晴らしいです。
  • 任意精度の浮動小数点が必要な場合、RubyBigDecimalもうまく機能し、それらが 10 進浮動小数点か 2 進浮動小数点かはあまり気にしません。
  • (科学的な) データを扱う場合、通常は固定精度の数値を扱っています。Ruby の組み込み float で十分でしょう。
  • あらゆる種類の浮動小数点演算がすべての状況で正確であるとは決して期待できません。
于 2010-06-14T20:56:13.880 に答える