两种舍入方法给出不同的结果

Two rounding methods give different results

提问人:Lapis 提问时间:6/18/2014 最后编辑:sawaLapis 更新时间:6/18/2014 访问量:167

问:

两种不同的浮点数舍入方法显示不同的结果。

"%.2f" % 0.015 # => "0.01" 
0.015.round(2) # => 0.02 

一个是字符串,另一个是浮点数。当舍入除 0.5 以外的任何内容时,它会正确舍入,或者与舍入函数相同。

"%.2f" % 0.01500000000000001 # => "0.02" 

此外,它并不总是那样表现:

[0.005, 0.015, 0.025, 0.035, 0.045, 0.055, 0.065, 0.075, 0.085, 0.095].map { |x| "%.2f" % x}
# => ["0.01", "0.01", "0.03", "0.04", "0.04", "0.06", "0.07", "0.07", "0.09", "0.10"]

我不确定这在技术上是否是一个错误,但至少它是非常违反直觉的。有谁知道为什么两种舍入方法的作用如此不同?

Ruby 舍入 点浮点精度

评论

1赞 tadman 6/18/2014
您希望找到哪种舍入方法?如果使用一致的舍入方法,将获得一致的结果。
0赞 Lapis 6/18/2014
在一种情况下,我需要它来保持浮点数,在另一种情况下,我需要一个字符串。有两个不同的结果是违反直觉的,并导致了一些坏错误。
0赞 tadman 6/18/2014
这不是一个错误,而是一个伪影,说明浮点数是多么疯狂,因为有些值不能准确表示,只能近似表示。使用定点数学或像BigDecimal这样设计得更慢但更一致的东西要安全得多。
0赞 statueuphemism 6/18/2014
我不是 ruby 专家,但是在一些 ruby 文档中搜索 sprintf,我没有看到任何可以保证 sprintf 实现舍入作为以指定精度打印浮点数的一部分。也许这就是问题所在。
2赞 tmyklebu 6/18/2014
@tadman:除零外,每个浮点数都有一个表示形式。您可以通过将两个有符号的零与零进行比较来区分它们(如果需要的话)。二进制浮点非常适合精确表示某些值。没有理由假设任何事情都是近似的,而事实并非如此。

答:

3赞 Pyrce 6/18/2014 #1

浮点值并不总是精确存储 - 相反,它们被存储为基数和指数,对于某些数字,它被精确地存储,而另一些则不然。对浮点数的任何修改都可能导致出现非常小的分数。因此,使用不同的舍入函数在边界处对某物进行舍入可以使它在两种可能的结果之间切换。

这样做会给你你想要的结果,因为我猜它的实现方式与浮动圆形方法不同。"%.2f" % 0.015.round(2)0.02%.2f

评论

0赞 tadman 6/18/2014
在操作应该如何和类似行为的背后有很多传统,这些传统继承自 C 语言的实现,可能只是始终如一地实现该行为。%sprintf
0赞 Pyrce 6/18/2014
这很有可能 - 也有可能 %.2f 假设某个字节大小的浮点/双精度值,这与特定 ruby 解释器使用的实际类型不同,并且完成了与 sprintf/C 类型匹配的强制转换。
0赞 Lapis 6/18/2014
我现在使用“%.2f” % 0.015.round(2)作为解决方法。IMO的真正问题是这两种方法之间的意外差异。
1赞 Pyrce 6/18/2014
嗯,一个是对字符串的强制,另一个是对另一个浮点数的强制(然后被强制到字符串以打印到控制台),所以从技术上讲,这两种方法在逻辑上并不等价。