【问题标题】:Proper way to compare decimal values in RSpec?在 RSpec 中比较十进制值的正确方法?
【发布时间】:2020-07-24 08:40:25
【问题描述】:

我有这个检查预期数字的规范:

  expect(animal_cost).to eq(0.7771118644067795e5)

我收到一条错误消息:

  expected: 77711.18644067795
        got: 0.7771118644067795e5

如您所见,我得到的数字与我预期的相同,所以我很困惑为什么会失败。如何设置规格?

animal_cost.class 是一个 BigDecimal。

【问题讨论】:

    标签: ruby-on-rails ruby rspec decimal


    【解决方案1】:

    使用 rspec 验证浮点数的最佳方法是使用 be_within 匹配器。浮点数不能以二进制形式在数学上完全准确地表示。肯定会有一些舍入误差。

    在你的情况下,你会写:

    expect(animal_cost).to be_within(0.001).of(0.7771118644067795e5)
    

    【讨论】:

      【解决方案2】:

      [animal_cost] 等于 0.7771118644067795e5 [...] 这是一个 BigDecimal

      这是一个浮点问题。您的 BigDecimal 值为 0.7771118644067795e5 的 精确 值为:

      77711.18644067795
      

      另一方面,float 77711.18644067795 的实际值为:(与大多数语言一样,Ruby 会截断浮点数)

      77711.186440677949576638638973236083984375
      

      根据比较,这些值可能会或可能不会被视为“相等”:

      d = BigDecimal('0.7771118644067795e5')
      f = 0.7771118644067795e5
      
      d == f      #=> true
      f == d      #=> true
      
      d.eql?(f)   #=> true
      f.eql?(d)   #=> false
      

      后者返回false,因为Float#eql? 就是这样工作的:

      eql?(obj) → 真或假

      仅当obj 是与float 具有相同值的Float 时才返回true

      为了使测试以准确的值通过,您应该使用BigDecimal 而不是浮点数:

      expect(animal_cost).to eq(BigDecimal('0.7771118644067795e5'))
      

      就个人而言,我会避免使用此类示例,因为您(显然)将结果复制到期望中。这个值是否正确并不明显。 (小数点后 11 位的“成本”对我来说似乎是错误的)尝试更改您的示例数据以获得可理解的结果,也可能是一个“整数”数字,例如70,000。

      【讨论】:

      • 确实如此。根据animal.cost 的货币(日元、英镑、美元),您最多只需要小数点后三位,对于 RSpec 测试而言,超过这三个位的精度可能是不必要的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-24
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 1970-01-01
      相关资源
      最近更新 更多