0

東西很古怪與小數和浮點數發生,我不明白爲什麼或者(的Ruby/Rails/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] 

Ruby和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) 

爲最糟糕的是,這並不與其他一些價值觀發生:

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,實用的解決方案是偉大的,但回答*爲什麼*有*的問題:「不這樣做」 *是適得其反。你甚至不知道它們是否是同一個問題。首先,另一個問題從兩個不同的數字開始。其次,兩位數的精度應該是漂浮物可以處理沒有問題的東西。第三,你可以看到問題在Ruby中,而在這裏我們無法檢測到問題(如示例所示)。 – ndn

+0

@ muistooshort,請重新打開它。我創建這個問題的原因是因爲我想更好地理解發生的事情。如果我想要一種辦法讓事情順利進行 - 我已經提出了一個解決方案。 – ndn

回答

0

這竟然是在軌道迴歸。它可以用5.0.0.1重現並沒有5.1.0.0 ???。


我平分一下,發現this commit是能解決的問題之一。這是相關的issue

的修復似乎是停止使用PG寶石的浮動編碼器。