3

私は ActiveRecord オブジェクトを持っています:

 s = Show.find 3980

Show にはlngDecimal 型 (精度 10、位取り 7) の列があります。私が電話lngした場合s

s.lng
#=> #<BigDecimal:7fac9a12ff40,'-0.821975E2',18(18)> 

すべてが良いです。しかし、私がこれを行うと:

s.lng == -82.1975
#=> false

返しますfalse!でもどっちも同じ!データベースの列が 10 進数であることに関係がありますか?

4

2 に答える 2

5

FPUの10進文字列の小数部が等しいかどうかを比較しないでください

したがって、1.8.7p330では:

BigDecimal.new('-82.1975') == -82.1975
 => true

しかし、1.9.3p194ではfalse.

問題は、浮動小数点または倍精度の値と、小数を含む10進定数との比較は、せいぜい信頼できないということです。

バイナリFP表現で正確な値を持つ10進文字列の小数部はほとんどありません。*たとえば、0.01から0.99の間では、0.25、0.50、および0.75のみが、繰り返されない正確なバイナリ表現を持ちます。これは、BigDecimalが存在する理由の約半分です。(理由の残りの半分は、FPデータの固定精度です。)

したがって、実際のマシン値を10進文字列定数と比較したときに得られる結果は、2進小数部のすべてのビットに依存します... 1/2 52まで...そして、それでも丸めが必要です。

数値を生成したプロセス、入力変換コード、またはその他の関連するものについて、ほんの少しでも不完全なものがある場合(hehe、bit、sorry)、それらは完全に同じようには見えません。

IEEE形式のFPUはその数値を正確に表すことさえできないため、比較は常に失敗するはずであるという議論がなされる可能性があります。

MySQLとActiveRecordは、何年にもわたって、分数を含む数値の正確な処理方法を変更してきました。

ただし、フロートをBigDecimalと混合しないようにする必要があります。つまり、次のように選択します。

BigDecimal.new('-82.1975')

それと比較してください。


*問題:マシン番号はx / 2 nですが、10進定数はx /(2 n * 5 m)です。

于 2012-12-24T22:29:15.443 に答える
0

してみてくださいs.lng.to_f == -82.1975

于 2012-12-24T21:43:32.593 に答える