【问题标题】:rspec big decimal matcherrspec 大十进制匹配器
【发布时间】:2014-12-03 19:26:38
【问题描述】:
-:total_cost_with_tax => #<BigDecimal:7fda9d17aaf0,'0.105225E4',18(45)>,
-:total_cost_without_tax => #<BigDecimal:7fda9d17b450,'0.972E3',9(36)>,
-:total_last_installment_amount => #<BigDecimal:7fda9d17b978,'0.8011E2',18(45)>,
-:total_monthly_installment_amount => #<BigDecimal:7fda9d17abb8,'0.8011E2',18(45)>,
-:total_tax => #<BigDecimal:7fda9d17b068,'0.8025E2',18(45)>,

+:total_cost_with_tax => #<BigDecimal:7fda9d0184c8,'0.105225E4',18(36)>,
+:total_cost_without_tax => #<BigDecimal:7fda91ff2b48,'0.972E3',9(27)>,
+:total_last_installment_amount => #<BigDecimal:7fda91fee548,'0.8011E2',18(36)>,
+:total_monthly_installment_amount => #<BigDecimal:7fda91fe72c0,'0.8011E2',18(36)>,
+:total_tax => #<BigDecimal:7fda9d00a2b0,'0.8025E2',18(36)>,

所以,这些在我的一些测试中散落一地... rspec 2,rails 3。我正在使用 .should eq() 比较哈希值进行比较。我似乎无法正确理解咒语。似乎这是一个精确的东西,这似乎很愚蠢。

【问题讨论】:

    标签: ruby-on-rails ruby rspec bigdecimal


    【解决方案1】:

    RSpec 3 有 BigDecimal eq:

    x.should eq(y)
    
    expect(x).to eq(y)
    

    如果您将 Bi​​gDecimal 与 Float 进行比较,请注意精度会影响比较。

    你可以用这个:

    x.should be_within(delta).of(y)
    
    expect x.to be_within(delta).of(y)
    

    如果您要比较两个具有不同精度的 BigDecimal 数字,请注意,这些数字可能会显示来自 inspecthash 的不同结果,具体取决于您的平台和您运行的 Ruby BigDecimal 版本。

    例如,可能会发生这种情况:

    BigDecimal.new("2").hash == BigDecimal.new("2.0").hash
    => false
    

    您的输出显示您的 BigDecimal 字符串表示形式略有不同。

    您的字符串的含义如下:

    • 第 1 部分是对象地址。
    • 第 2 部分是表示为字符串的数值。
    • 第 3 部分是有效位数,然后是最大有效位数。

    您的输出显示您的字符串具有不同的对象地址、相同的数值(即第 2 部分)、相同的有效数字(第 3 部分中的第一个数字),但最大有效数字的数量不同。

    对于您的问题,使用 RSpec 2 并比较 BigDecimal 哈希,您将通过使用 rspec be_within 匹配器来解决您的问题。

    请注意,Ruby BigDecimal 数字和 Float 数字都是浮点数:

    • BigDecimal 是任意精度的十进制浮点数。

    • Float 是本机架构的双精度二进制浮点数。

    您可以通过执行以下操作查看BigDecimal 十进制浮点表示:

    require 'bigdecimal'
    x=BigDecimal.new(100)
    => #<BigDecimal:7f8e62038570,'0.1E3',9(27)>
    

    有效数字部分是'0.1',指数部分是'E3'。

    请注意,这适用于典型的 Ruby MRI/KRI 虚拟机。其他 Ruby VM(例如 JRuby)上的实现可能会有所不同,因为 Java 有自己的 bignum 代码。

    当您比较两种不同类型的浮点数(例如 BigDecimal 和 Float)时,您可能会得到看似违反直觉的结果,因为这些类型使用不同的基数(十进制与二进制)、不同的精度和不同的 Ruby类。

    例子:

    BigDecimal.new("1.111111111111111") === 1.111111111111111
    => true
    BigDecimal.new("1.1111111111111111") === 1.1111111111111111
    => false
    

    【讨论】:

    • 郑重声明:不正确。使用 BigDecimal 的全部意义在于它表现得像一个浮点数;你应该得到你输入的数字。
    • @Andy 我添加了更多细节来解决您的评论。
    • 很好,但我的评论的重点是您不应该需要使用be_within 来匹配BegDecimal。它不像浮动;由于数字的存储方式,您无需考虑舍入误差。
    • @Andy 您在典型情况下是正确的,但对于 OP 比较哈希的情况,在他编写它时,使用 RSpec 2,并且不知道平台。我添加了更多细节供您查看。
    【解决方案2】:

    在 Rspec 3.x 中,您可以将 eq 匹配器用于 BigDecimal,就像您可以将其用于浮点数一样。

    RSpec.describe "an integer" do
      it "is equal to a float of the same value" do
        expect(5).to eq(5.0)
      end
    end
    

    有关更多信息,请参阅 RSpec 文档: https://www.relishapp.com/rspec/rspec-expectations/v/3-4/docs/built-in-matchers/equality-matchers

    【讨论】:

    • @damoiser 当 RSpec 是第 2 版而不是第 3 版时,有人问了这个问题。我现在将更新我的答案以显示两者,因为我同意你的观点。
    猜你喜欢
    • 2011-11-09
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多