2015-02-08 68 views
0

我有需要Float属性和相应的表的活动记录模式:避免浮动截断4

# app/models/test.rb 
class Test < ActiveRecord::Base 
end 

# db/schema.rb 
ActiveRecord::Schema.define(version:20150208185300) 

    enable_extension "plpgsql" 

    create_table "tests", force: true do |t| 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.float "size" 
    end 

end 

当我坚持一个测试一切正常:

Test.create(size: 271893999999.99997) 
#=> #<Test id: 1, created_at: "2015-02-07 19:43:22", updated_at: "2015-02-07 19:43:22", size: 271893999999.99997> 

然而,当检索测试的大小它回来截断:

Test.last.size 
#=> 271894000000.0 

而且是当尽管误导输出坚持,当我创建它也被截断:

Test.last 
#=> #<Test id: 1, created_at: "2015-02-07 19:43:22", updated_at: "2015-02-07 19:43:22", size: 271894000000.0> 

这个问题困扰我,因为我可以做以下的红宝石:

a = 123456789.123456789 
#=> 123456789.123456789 
a.class 
#=> Float 
a 
#=> 123456789.123456789 

什么是Rails的使用Float的限制/ Postgres的?如果我想要5位小数的精确度,我应该使用Decimal吗?

我用Rails 4.1.1和Postgres 9.3.5

回答

2

什么是Rails的/ Postgres的使用浮动的限制?

PostgreSQL支持浮动使用标识符浮动真正点数。标识floatreal是同义词。在大多数电脑上,floatreal会给你至少6位的小数精度。这是小数精度的六位数字。

Test.last.size 
#=> 271894000000.0 
    ^^^^^^ 

在大多数计算机上,会给你分数精确度至少15位。 Ruby's float相当于PostgreSQL的double,而不是PostgreSQL的real

如果我想要5位小数的精确度,我应该使用小数吗?

短语我想要的5个小数点准确性 [原文]没有很好地转化为浮点数据类型。当你写这样的东西

Test.create(size: 271893999999.99997) 

你不是问PostgreSQL的小数点右边的五位数。你要求17位数的小数精度。浮点数据类型不太可能为您提供那么高的精度。

而不是浮动,你需要使用任意精度的数据类型。在数据库方面,它看起来像

numeric(17, 5) 
decimal(17, 5) 

这两个声明都给你17位精度,最多5位数字在小数点右边。

在Rails迁移中,您可能会这样做。

add_column :your_table, :your_column, :decimal, :precision => 17, :scale => 5 


什么你在这里看到的

Test.last.size 
#=> 271894000000.0 

没有截断或者四舍五入,严格地说。这是“近似误差”。值271893999999.99997不在数据库域float中,因此PostgreSQL使用该域中最接近的值。该值恰好是271894000000.0


PostgreSQL numeric data types

1

使用Decimal并指定精度您的数据库规模,所以,你一定要有准确的计算。

Take a look at short example

+0

我还是不明白,为什么我不能用浮法这个任务 - 它们能够处理的Rails之外,许多小数。这是Postgres的限制吗? – garythegoat 2015-02-08 23:42:26