0

何か非常に奇妙な小数と浮動小数点で起こっていると私は理由(ルビー/レール/ postgresql)を理解することはできません。奇妙な丸め問題

p1 = Purchase.where(total: 5.99).first_or_create 
p2 = Purchase.where(total: 5.99).first_or_create 

[p1.id, p2.id] # => [1, 2] 

p3 = Purchase.where(total: 5.99.to_d).first_or_create 
p4 = Purchase.where(total: 5.99.to_d).first_or_create 

[p3.id, p4.id] # => [1, 1] 

ルビーとPostgreSQLの両方が正確に5.99を表す何の問題に関係なく、小数または浮く場合がありません:

5.99.to_s   # => "5.99" 
5.99.to_d.to_s # => "5.99" 
5.99 == 5.99.to_d # => true 

SELECT CAST(5.99 AS DECIMAL) AS decimal, CAST(5.99 AS FLOAT) AS float; 
    # decimal | float 
    # ---------+------- 
    #  5.99 | 5.99 
    # (1 row) 

SELECT CAST(5.99 AS DECIMAL) = CAST(5.99 AS FLOAT) AS equal; 
    # equal 
    # ------- 
    # t 
    # (1 row) 
- 10進数の列と 購入テーブルを考えると

これをすべて無効にするには、他の値では発生しません。

p5 = Purchase.where(total: 5.75).first_or_create 
p6 = Purchase.where(total: 5.75).first_or_create 
p7 = Purchase.where(total: 5.75.to_d).first_or_create 

[p5.id, p6.id, p7.id] # => [3, 3, 3] 
+0

基本的には、 'total'をどこでも浮動小数点値にすることは決してありません。代わりに' 5.99'.to_d'のようなものを言いたいと思うでしょう。 –

+0

@muistooshort、実用的な解決策は素晴らしいですが、なぜ*「*しないでください」という質問に答えるのは、生産性が低いことです。あなたは同じ問題であるかどうかも分かりません。まず、別の質問は2つの異なる数字から始まります。第2に、2桁の精度は浮動小数点が問題なく処理できるものでなければなりません。第3に、問題はRubyにありますが、ここでは問題を検出できません(例に示すように)。 – ndn

+0

@muistooshort、これを再度開いてください。この質問を作成した理由は、何が起こっているのかをより深く理解したいからです。物事がちょうどうまくいく道が欲しかったら - 私はすでに問題の解決法を提供しています。 – ndn

答えて

0

これはレールの回帰であることが判明しました。それは5.0.0.1で再現可能ですか? 5.1.0.0で消えてしまいました。


私はそれを二等分し、this commitが問題を解決するものであることを発見しました。これは関連するissueです。

この修正は、pg gemのfloatエンコーダの使用を中止することです。