在Ruby中不进行四舍五入的浮点数格式化

6

有一个浮点数num = 22.0098,我该如何格式化它以限制小数点后3位?我尝试过sprintf('%.3f',num)但返回值是22.010,我需要的是22.009


1
以上链接还包括一个简单的解决方案:sprintf('%.3f', num - 0.0005) - Stefan
3个回答

8

我认为可以使用BigDecimal,但不确定是否过于复杂:

require 'bigdecimal'   
BigDecimal::new("22.0098").truncate(3).to_f
#=> 22.009

抱歉,根据要求,不允许使用宝石。 - Nodir Nasirov
5
@NodirNasirov,这不是第三方宝石。BigDecimal 是 Ruby 内置的支持。 - shivam

4

很不幸,与Float#round不同的是,Float#floor不接受数字数量。下面的代码实现了所需的行为。

def floor_float input, digits = 3
  input.divmod(10 ** -digits).first / (10 ** digits).to_f  
end 

这可能被用作猴子补丁:

class Float
  def floor_ext digits = 3
    self.divmod(10 ** -digits).first / (10 ** digits).to_f  
  end 
end
22.0098.floor_ext
#⇒ 22.009

根据@Stefan的建议,以下是更加简洁的变体:

class Float
  def floor_ext digits = 3
    div(10 ** -digits).fdiv(10 ** digits)
  end 
end
22.0098.floor_ext
#⇒ 22.009

或者,也可以直接处理字符串:
i, f = 22.0098.to_s.split('.')
#⇒ [ "22", "0098" ]
[i, f[0..2]].join('.')
#⇒ "22.009"

你可以更简洁地表达它:input.div(10 ** -digits).fdiv(10 ** digits)。此外,在 Float 中,你可以省略 self - Stefan
1
大致上是可以的,但严格来说,在0到1之间有大约367个IEEE双精度数会被错误地四舍五入为3位小数。例如,最接近0.009的Float小于9/1000(确切地说是0.00899999999999999931998839741709161899052560329437255859375),尽管它会被打印成“0.009”。由于这个Float的最短十进制表示是“0.009”,这可能看起来是正确的答案并符合OP要求,但从技术上讲却不是正确的。 - aka.nice

1
如果你知道整数部分有多少位数,你可以将其格式化为字符串:
sprintf("%.6s", num)
# => "22.009"

一般来说,您可以根据num的大小调整6

1
我不知道整数部分的位数。 - Nodir Nasirov

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