Ruby四舍五入向上或向下浮动到特定的十进制有效数字

jsm*_*rtt 3 ruby floating-point rounding floor ceil

我正在使用 Ruby 2.3.1,这是我想要做的:

1.33333333.ceil(2) -> 1.34
1.33333333.floor(3) -> 1.333
Run Code Online (Sandbox Code Playgroud)

Float#round方法允许我舍入,但我需要能够指定是向上还是向下舍入,类似于#ceil#floor方法,但带有一个参数来指定要保留的小数位数。

jsm*_*rtt 5

Ruby 2.4+ 中Float#float&Float#ceil方法接受一个ndigits参数:

1.33333333.ceil(2) -> 1.34
1.33333333.floor(3) -> 1.333
Run Code Online (Sandbox Code Playgroud)

但是,请使用这些 STD lib 方法检查此行为:

# In Ruby 2.4.2:
0.07.ceil(2) -> 0.08
1.1.ceil(2) -> 1.11
Run Code Online (Sandbox Code Playgroud)

在我的书中不好。

对于较旧的 Ruby 版本,或者如果您想获得比 STB 库提供的更好的结果,则需要编写自己的方法。有一些不同的博客文章,稍后我将解释为什么它们不是始终正确的,但这里有一些方法每次都应该正确工作:

require 'bigdecimal'

class Float
  def ceil2(exp = 0)
    BigDecimal(self.to_s).ceil(exp).to_f
  end

  def floor2(exp = 0)
    BigDecimal(self.to_s).floor(exp).to_f
  end
end
Run Code Online (Sandbox Code Playgroud)

现在了解更多关于为什么以下不正确的信息

def ceil_to(x)
  (self * 10**x).ceil.to_f / 10**x
end

def floor_to(x)
  (self * 10**x).floor.to_f / 10**x
end

# These methods also produce bad results for the examples shown above
0.07.ceil(2) -> 0.08
1.1.ceil(2) -> 1.11
Run Code Online (Sandbox Code Playgroud)

我不会详细介绍正在发生的事情(您可以在此处此处找到 ),但浮点运算可能很混乱,并且确实会发生舍入错误。