两种舍入方法会得出不同的结果。

3

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

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

一个是字符串,另一个是浮点数。当四舍五入不为0.5时,它会正确地四舍五入,或者与round函数以同样的方式四舍五入。

"%.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"]

我不确定这是否技术上算是一个bug,但至少它非常令人费解。有人知道为什么两种取整方法会有如此不同的表现吗?


1
你想要找哪种舍入方法?如果你使用一致的舍入方法,你将得到一致的结果。 - tadman
在某些情况下,我需要它保持为浮点数类型;而在另一种情况下,我则需要一个字符串。这产生了两个不同的结果,非常违反直觉,并导致了一些严重的错误。 - Lapis
这不是一个错误,而是浮点数的一种特殊表现形式,因为某些值无法准确表示,只能近似。使用定点数学或类似 BigDecimal 的东西更安全,虽然速度较慢但更加一致。 - tadman
可能是重复的问题:浮点数运算是否存在问题? - tmyklebu
2
@tadman:除零外,每个浮点数都有一个表示。如果您需要区分两个有符号的零,则可以将它们的倒数与零进行比较。二进制浮点在准确表示某些值方面非常出色。当事情不是近似时,没有理由假设任何东西是近似的。 - tmyklebu
显示剩余5条评论
1个回答

3
浮点数并不总是精确存储的 -- 它们被存储为一个基数和指数,对于某些数字来说,它们被完全精确地存储,而对于其他数字则不是。任何对浮点数的修改都可能导致非常小的分数出现。因此,在边界处进行不同舍入函数的四舍五入可能会使其在两种可能的结果之间切换。
执行"%.2f" % 0.015.round(2)将给您想要的0.02结果,我猜%.2f的实现方式与浮点数的round方法不同。

%和类似sprintf的操作背后有很多传统,这些传统继承自C语言的实现。可能只是在一致地实现这种行为。 - tadman
很有可能 - 同时也有可能%.2f假设了一个特定的字节大小的浮点/双精度浮点数,而这个大小与特定的Ruby解释器使用的实际类型不同,并且进行了匹配sprintf / C类型的强制转换。 - Pyrce
我目前使用"%.2f" % 0.015.round(2)作为解决方法。但在我看来,真正的问题是这两种方法之间的意外差异。 - Lapis
1
一个是强制转换为字符串,另一个是强制转换为另一个浮点数(然后强制转换为字符串以便在控制台上打印),因此从逻辑上讲,这两种方法并不等价。 - Pyrce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接