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宝石的浮动编码器。