ruby to_f bug或乘法运算符bug?

时间:2011-10-24 17:47:06

标签: ruby rounding multiplication

嗨,我刚遇到一个ruby的to_f函数给我的结果不一致的问题。

ruby-1.9.2-head :026 > 8.45.to_f * 100
 => 844.9999999999999 

ruby-1.9.2-head :027 > 4.45.to_f * 100
 => 445.0 


ruby-1.9.2-head :028 > 4.35.to_f * 100
 => 434.99999999999994 

我的解决方法是简单地以这种方式对结果进行舍入

ruby-1.9.2-head :029 > (4.35.to_f * 100).round
 => 435 

经过多次游戏,我意识到问题可能出在乘法运算符* 100

4 个答案:

答案 0 :(得分:5)

欢迎来到浮点漂移。这是一个很好理解的问题,你应该阅读,所以你至少要自己理解。例如,看看下面的文章:

答案 1 :(得分:1)

已经提到了Float的问题。请参阅其他答案。

更多评论:

你写了4.35.to_f。在这种情况下,to_f不是必需的。 4.35已经是Float:

p 4.35.class #-> Float

你在哪里认识到这个问题。当您打印数字时,该值已经舍入。 使用String#%,您可以确定输出的详细信息级别:

p 8.45.to_f * 100 #->845.0
p "%.12f" % (8.45.to_f * 100) # -> "845.000000000000"
p "%.13f" % (8.45.to_f * 100) # -> "844.9999999999999"
p "%.14f" % (8.45.to_f * 100) # -> "844.99999999999989"
p "%.16f" % (8.45.to_f * 100) # -> "844.9999999999998900"

答案 2 :(得分:0)

唉,这是浮点数学的诅咒的一部分,而不仅仅是Ruby中的一个问题:

http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding

如果您需要精确的小数运算,请使用BigDecimal:

require 'bigdecimal'

(BigDecimal('4.35') * 100).to_f
  #=> 435.0 

答案 3 :(得分:0)

基本问题是分数45/100没有精确表示为1/2 n 项的序列。实际上,使用少量基数为10的数字写的大多数分数没有精确的FP表示。

因此,您得到的实际数字与您的基数为10的数字非常接近但不完全相近。输出结果将取决于您舍入的位置,但如果您在舍入时做任何最合理的事情,那么输出结果将是正确的。

如果你不圆,你获得的确切数字将取决于分数被切断的位置以及你试图转换的数字。分数被斩波的位置将取决于表示尾数需要多少位。这就是为什么你得到 x .45的不同结果,取决于 x。

这个问题一直出现在堆栈溢出上。我想我们需要一个浮点常见问题。

具有讽刺意味的是,每个(范围内)整数值 都具有精确的浮点格式表示。