Ruby Float#round方法与round(2)行为不正确 [英] Ruby Float#round method behaves incorrectly with round(2)

查看:905
本文介绍了Ruby Float#round方法与round(2)行为不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道建议使用 BigDecimal 而不是 Float ,但这个是bug或高亮 Float 的深奥特性。看来 Float#round(2)存在1.015,1.025和1.035的问题。

  1.015.round(2)
=> 1.01#=> WRONG ..应该是1.02
1.025.round(2)
=> 1.02#=> WRONG ..应该是1.03
1.035.round(2)
=> 1.03#=> WRONG ..应该是1.04
1.045.round(2)
=> 1.05#=>正确
1.016.round(2)
=> 1.02#=>正确

round(3)正常工作。

  1.0015.round(3)
=> 1.002#=>正确
1.235.round(2)
=> 1.24#=>正确的

为了在一个Rails应用程序中修补这个问题,我这样做了:

  config / initializers / float_mp.rb 

require'bigdecimal'

class Float
def round(val = 0)
BigDecimal.new(self.to_s).round(val).to_f
end
end

这似乎是一个奇怪和昂贵的解决方法。这可能是 Float#round

解决方案

中的错误AFAICS红宝石圆()正常工作。可能它只是libm中round()函数的一个包装。

所以原因在于你的浮点文字不能完全用二进制表示。例如。用小数点打印的1.015给出1.0149999999999999;因此当四舍五入到两位小数时,1.01比1.02更接近真值。另外请记住,默认的IEEE 754舍入模式是舍入到最近,连接到偶数,这不是同圆到最近,从零开始,这是你可能从学校熟悉的。


I learned that it's recommended to use BigDecimal instead of Float, but this one is either a bug or highlights the esoteric nature of Float. It seems that Float#round(2) has a problem with "1.015", "1.025" and "1.035".

1.015.round(2)
 => 1.01    # => WRONG .. should be 1.02
1.025.round(2)
 => 1.02    # => WRONG .. should be 1.03
1.035.round(2)
 => 1.03    # => WRONG .. should be 1.04
1.045.round(2)
 => 1.05    # => CORRECT
1.016.round(2)
 => 1.02    # => CORRECT

round(3) works fine.

1.0015.round(3)
 => 1.002  # => CORRECT
1.235.round(2)
 => 1.24   # => CORRECT 

To monkey patch this in a Rails app, I did this:

config/initializers/float_mp.rb

require 'bigdecimal'

class Float
  def round(val=0)
     BigDecimal.new(self.to_s).round(val).to_f
  end
end

This seems to be a weird and expensive work-around. Could this be a bug in Float#round?

解决方案

AFAICS the ruby round() works correctly. Presumably it's just a wrapper around the round() function in libm anyway.

So the reason is that your floating point literals cannot be represented exactly in binary. E.g. "1.015" printed with a few more decimals gives "1.0149999999999999"; thus when rounding to two decimal digits, 1.01 is closer to the true value than 1.02. And so on for your other examples as well.

Also keep in mind that the default IEEE 754 rounding mode is "Round to nearest, ties to even" which is not the same as "Round to nearest, ties away from zero" which is what you may be familiar with from school.

这篇关于Ruby Float#round方法与round(2)行为不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆