【问题标题】:Ruby on Rails decimal comparison stopped workingRuby on Rails 十进制比较停止工作
【发布时间】:2019-01-06 17:08:07
【问题描述】:

我一直在数据库中使用状态对象来跟踪已加载到其中的种子数据。表结构为:

create_table "toolkit_states", force: :cascade do |t|
  t.boolean "signups", default: true
  t.decimal "database_version", precision: 5, scale: 2
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

seeds.rb 文件检查 database_version 并运行代码块,然后在运行代码块后设置 database_version。从 0.1 到 0.55 版本都运行良好。

我添加了一个新的种子数据块。要运行该块,请检查 database_version,它应该是 0.56。以下比较不起作用:

if state.database_version == 0.56

由于某种原因,无法评估数字 0.56 是否与存储在数据库中的值相等。它适用于高达 0.56 的所有值。

这是一个 Rails 控制台会话:

irb(main):001:0> state = ToolkitState.first
ToolkitState Load (0.4ms)  SELECT  "toolkit_states".* FROM "toolkit_states" ORDER BY "toolkit_states"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<ToolkitState id: 1, signups: false, database_version: 0.56e0, created_at: "2018-12-27 17:04:50", updated_at: "2018-12-27 17:04:56">
irb(main):002:0> state.database_version == 0.56
=> false
irb(main):003:0> state.database_version == 0.56e0
=> false
irb(main):004:0> state.database_version == 0.56.to_f
=> false
irb(main):005:0> state.database_version.to_f == 0.56
=> true

当我用“to_f”转换值时,比较有效。我的问题是,如果没有这个转换到 0.56 的值,它也能正常工作

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    这是因为state.database_versionBigDecimal 类的一个实例。 This article 解释为什么是BigDecimal

    看这个例子:

    BigDecimal('0.56e0')
    => 0.56e0
    irb(main):008:0> BigDecimal('0.56e0') == 0.56
    => false
    irb(main):009:0> BigDecimal('0.56e0').to_f
    => 0.56
    

    如您所见,0.56e0 转换为 float 后类型变为 0.56,您的比较返回 true。

    Nate 更简要地解释了为什么会发生这种情况in this comment

    【讨论】:

    • 为什么直到 0.56 才进行比较?谢谢你提供的详情。从现在开始,我只是在比较之前转换它。
    【解决方案2】:
    irb(main):001:0>  c = BigDecimal('0.56e0')
    => 0.56e0
    irb(main):002:0> c == 0.56
    => false
    irb(main):003:0>  c = BigDecimal('0.55e0')
    => 0.55e0
    irb(main):004:0> c == 0.55
    => true
    

    适用于 0.55 而不是 0.56 Rails 错误?

    【讨论】:

    • BigDecimal 和 Float 都是 Ruby 核心类,而不是 Rails。这个问题其实和 Rails 无关。这可能是浮点精度不一致。比较浮动总是很危险的。以下问题详细说明了浮点数如何不如 BigDecimals 精确,并且在某些情况下,您最终得到的数字与您预期的几乎相同但不完全相同。 stackoverflow.com/q/3039650/10068463
    猜你喜欢
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 2015-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    相关资源
    最近更新 更多