【问题标题】:Ruby BigDecimal and MySQL decimal precision mismatchRuby BigDecimal 和 MySQL 小数精度不匹配
【发布时间】:2011-01-20 23:20:21
【问题描述】:

我使用 Rails 3.0.3 在 MySQL 数据库中存储了一些纬度和经度。这是我用来创建表的迁移的一部分(注意具有给定精度的十进制值):

create_table :dummies do |t|
  t.decimal :something, :precision => 13, :scale => 10
end

下面的 RSpec 示例应该说明哪里出了问题。

我使用 BigDecimal 进行一些计算,得到的 my_value 是一个精度很高的数字(大于迁移中指定的数字)。我将对象存储在数据库中并再次检索它。

将原始值与数据库值进行比较失败,因为它们的精度不同,因此不再是相同的数字:

it 'should be equals before and after save' do
  my_value = BigDecimal('4.123456789') * 5000 # more precise than defined in the migration
  dummy = Dummy.new(:something => my_value)
  location.save!
  Dummy.first.something.should == dummy.something
end

我明白为什么会发生这种情况(MySQL 中的小数精度!= BigDecimal 的精度),但谁能告诉我如何在将 my_value BigDecimal 的精度写入数据库以确保它尊重数据库约束吗?

谢谢!

【问题讨论】:

    标签: mysql ruby-on-rails-3 decimal precision bigdecimal


    【解决方案1】:

    在 mySQL 中,使用 FLOAT 来存储这些地理坐标。将它们存储为高精度十进制是没有意义的。请记住,纬度的 1/60 度是海里,因此一英尺(约 1/3 米)约为 3 微度。 (3e-06)

    IEEE 单精度浮点的 epsilon(误差)约为 6e-08

    GPS 和地理编码没有那么详细,即使您处于 179.9996 度。

    如果您要制作高度详细的 200 比例地形图或类似的东西,您可能已经知道必须使用高精度投影,例如通用横向墨卡托或兰伯特等,因为您超出了限制将地球近似为一个球体。但是,如果您正在开发商店查找器类型的应用程序,则不需要、不想也无法获得这种精度。

    如果您必须在 Ruby 程序中使用小数,请在存储到 mySQL 之前转换为浮点数。

    这是 Randall Munroe 对地理坐标精度的解释。

    【讨论】:

    • 谢谢奥利。问题是我稍后会使用坐标进行计算,这就是我使用 BigDecimal 的原因,认为浮点数可能会在这里返回奇怪的值,不是吗?我将尝试您的最后一个解决方案,在验证之前转换为浮点数。
    • @Cimm -- 浮点数适用于这些计算。说真的。
    • 再次感谢!我选择了t.float :latitude, :limit => 51,它在 Rails 中使用 Float 并将值作为 Double 存储在 MySQL 中。
    • 我不明白这一切。但看起来你知道你在说什么。我会听取你的建议。
    【解决方案2】:

    我会尝试类似的东西

    new_value = number_with_precision(your_value.to_f, :precision => 13)
    

    【讨论】:

    • 感谢 Dimitri,似乎在保存到数据库之前转换为浮点数是可行的方法。 'number_with_precision' 方法是一个视图助手,它不能在模型中使用,所以我认为这不会有帮助。
    猜你喜欢
    • 2016-05-27
    • 1970-01-01
    • 2012-07-18
    • 2013-06-27
    • 1970-01-01
    • 2013-03-05
    • 2020-07-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多