从数据库出来后,为什么我的小数略大?

时间:2012-10-09 22:01:37

标签: ruby-on-rails ruby sqlite activerecord

我对进出数据库后获得额外0.000000000000000001(左右)的2位十进制感到有点困惑。

这就是我所做的:( Rails 3.2.8)

创建了迁移:

class CreateItems < ActiveRecord::Migration
  def change
    create_table :items do |t|
      t.column :price, :decimal, :precision => 16, :scale => 2
    end
  end
end

创建了一个模型:

class Item < ActiveRecord::Base
end

然后:

$ rails c
>> i = Item.new
>> i.price = 9.46
>> i.save
>> Item.first.price
=> #<BigDecimal:46b3768,'0.9460000000 000001E1',27(45)>

这是一个SQLite数据库,在那里看起来都很好:

$ rails db
>> select * from items;
1|9.46

请注意,我注意到的唯一数字是9.46。 额外的0.00000000000001来自哪里?


编辑我知道如果没有小错误,某些数字的浮点表示是不可能的。但为什么Item.first.price不等于BigDecimal.new('9.46')? SQLite存储一个浮点数而不是一个整数,并且应该将它除以10(这是我对十进制列的期望)?或者在ActiveRecord中有一些问题,我不知道从数据库中检索值?见下文:

$ rails c
>> decimal = BigDecimal.new('9.46')
>> Item.first.price == decimal
=> false

3 个答案:

答案 0 :(得分:1)

9.46不能完全表示为IEEE double - 精度浮点数。这有a great many consequences,但在这里意味着您获得了可以准确表示的值,并且最接近您放入的值。

如果你得到'9.46'是至关重要的,请将其存储在TEXT亲缘关系的列中(并注意你存储的是字符串,而不是“数字”)。< / p>

答案 1 :(得分:1)

我建议您阅读这篇文章:What Every Computer Scientist Should Know About Floating Arithmetic

该文章的tl; dr版本......

  

将无数多个实数压缩成有限数量的位   需要近似的表示。虽然有无限的   许多整数,在大多数程序中,整数计算的结果都可以   以32位存储。相反,给定任意数量的位,   大多数带有实数的计算都会产生数量   不能使用那么多位来精确表示。因此   浮点计算的结果通常必须按顺序舍入   以适应其有限的表示。这个舍入误差是   浮点计算的特征。

答案 2 :(得分:1)

我对ruby不是很熟悉,但不是使用

i.price = 9.46

尝试使用

i.price = BigDecimal.new('9.46')