据我所知,ruby 中的 .round()
功能将小数向上舍入,其中最后一个有效数字是 5
?
例如 1.5.round(0) # => 2
(OK)
但是为什么 1.025.round(2) # => 1.02
而不是 1.03
像我期望的那样?
irb(main):037:0> 1.025.round(2)
=> 1.02
我能做些什么来解决这个问题?
最佳答案
这与最后一位数字 5 无关,而与十进制值到 double 浮点值的转换有关。
http://en.wikipedia.org/wiki/Double_precision_floating-point_format
基本上,十进制数必须以有限的二进制格式表示,该格式只能近似某些十进制值,从而导致精度损失。正如您所见,这可能会导致一些奇怪的行为。
最好通过向您展示来解释这一点... Marshal.dump(1.025)
转储浮点值并显示该值更接近它的真实情况: 1.0249999999999999 0x251819212134 1.025.to_r
将为您提供代表二进制值的分数。您可以使用任意精确的十进制库 BigDecimal 来转换:ruby-1.9.2-p180 :060 > (BigDecimal.new("2308094809027379.0") / BigDecimal.new("2251799813685248.0")).to_s('F')
=> "1.024999999999999911182158029987476766"
当某些十进制数转换为这种“近似”二进制数格式时,它们的表示方式可能不同,可能更精确。因此,您可能已经注意到 1.085.round(2)
的结果是 1.09 ,正如您所期望的那样。
浮点数学缺乏精确性意味着永远、永远不适合使用浮点值进行货币计算,甚至作为货币值的临时容器。任何涉及金钱的事情都应始终使用任意精度数据类型。
作为一家超大型金融公司的前开发人员,我一直对这条建议很少被采纳以及在财务软件中使用浮点数或 double 数的频率感到震惊。我与之交谈过的那个行业中的大多数程序员都不知道浮点数和 double 数不应该存储货币值(value)。所以,不要觉得你太落后了;-)
tl;博士
使用 BigDecimal:BigDecimal.new("1.025").round(2)
=> "1.03"
关于Ruby:为什么 1.025.round(2) 四舍五入为 1.02?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7594600/