如何在Ruby中将浮点数四舍五入到指定的有效位数



如果在Ruby中有一个类似R的signif函数就好了。

例如:

>> (11.11).signif(1)
10
>> (22.22).signif(2)
22
>> (3.333).signif(2)
3.3
>> (4.4).signif(3)
4.4 # It's usually 4.40 but that's OK. R does not print the trailing 0's
    # because it returns the float data type. For Ruby we want the same.
>> (5.55).signif(2)
5.6

可能有更好的方法,但这似乎工作得很好:

class Float
  def signif(signs)
    Float("%.#{signs}g" % self)
  end
end
(1.123).signif(2)                    # => 1.1
(11.23).signif(2)                    # => 11.0
(11.23).signif(1)                    # => 10.0

这是一个不使用字符串或其他库的实现。

class Float
  def signif(digits)
    return 0 if self.zero?
    self.round(-(Math.log10(self).ceil - digits))
  end
end

我在Float中没有看到这样的东西。Float主要是本机double类型的包装器,并且考虑到通常的二进制/十进制问题,我并不惊讶Float不允许您操作有效数字。

然而,标准库中的BigDecimal可以理解有效数字,但是我没有看到任何允许你直接改变BigDecimal中的有效数字的东西:你可以请求它,但你不能改变它。但是,您可以通过使用multadd方法的无操作版本来解决这个问题:

require 'bigdecimal'
a = BigDecimal.new('11.2384')
a.mult(1, 2) # the result is 0.11E2   (i.e. 11)
a.add(0, 4)  # the result is 0.1124E2 (i.e. 11.24)

这些方法的第二个参数:

如果指定且小于结果的有效位数,则根据BigDecimal.mode将结果四舍五入到该位数。

使用BigDecimal会比较慢,但是如果你需要细粒度的控制或者如果你需要避免常见的浮点问题,它可能是你唯一的选择。

之前的一些答案和评论都提到了这个解决方案,但这对我来说是有效的:

# takes in a float value and returns another float value rounded to 
# given significant figures.    
def round_to_sig_figs(val, sig_figs)
  BigDecimal.new(val, sig_figs).to_f
end

您可能正在寻找Ruby的Decimal。

你可以这样写:

require 'decimal/shortcut'
num = 1.23541764
D.context.precision = 2
num_with_2_significant_digits = +D(num.to_s) #  => Decimal('1.2')
num_with_2_significant_digits.to_f #  => 1.2000000000000002

或者,如果您喜欢使用相同的语法,将此作为函数添加到类Float中,如下所示:

class Float
  def signif num_digits
    require 'decimal/shortcut'
    D.context.precision = num_digits
    (+D(self.to_s)).to_f
  end
end

的用法将是相同的,即

 (1.23333).signif 3
 # => 1.23

要使用它,安装gem

gem install ruby-decimal

@Blou91的答案几乎在那里,但它返回一个字符串,而不是一个浮点数。

(sprintf "%.2f", 1.23456).to_f

作为一个函数,

def round(val, sig_figs)
  (sprintf "%.#{sig_figs}f", val).to_f
end

如果你想打印末尾的零,可以使用sprintf

2.0.0-p353 :001 > sprintf "%.3f", 500
 => "500.000"
2.0.0-p353 :002 > sprintf "%.4f", 500
 => "500.0000"
2.0.0-p353 :003 >

相关内容

  • 没有找到相关文章

最新更新