有时,Activerecord数据类型让我感到困惑。呃,经常。对于特定情况,我的一个永恒问题是
我应该使用
:decimal
还是:float
?
我经常遇到这个链接 ActiveRecord: :decimal vs :float? ,但答案不够清楚,我无法确定:
我见过许多线索,人们建议不要使用 浮点数并始终使用小数。我也看到过一些人的建议 人们只将浮法用于科学应用。
以下是一些示例案例:
-45.756688
,120.5777777
,... 0.9
,1.25
,1.333
,1.4143
,... 我过去曾使用:decimal
,但我发现与浮点数相比,处理Ruby中的BigDecimal
对象是不必要的尴尬。例如,我也知道我可以使用:integer
代表金钱/美分,但它并不适合其他情况,例如精确度随时间变化的数量。
答案 0 :(得分:397)
我记得我的CompSci教授说永远不会使用花车作为货币。
原因是二进制格式的IEEE specification defines floats。基本上,它存储符号,分数和指数来表示浮点数。它就像二进制的科学记法(类似+1.43*10^2
)。因此,不可能在Float中精确存储分数和小数。
这就是为什么有一个十进制格式。如果你这样做:
irb:001:0> "%.47f" % (1.0/10)
=> "0.10000000000000000555111512312578270211815834045" # not "0.1"!
而如果你这样做
irb:002:0> (1.0/10).to_s
=> "0.1" # the interprer rounds the number for you
因此,如果您正在处理小部分,例如复合利益,甚至地理位置,我强烈推荐使用十进制格式,因为十进制格式1.0/10
正好是0.1。
然而,应该注意的是,尽管不太准确,浮子的处理速度更快。这是一个基准:
require "benchmark"
require "bigdecimal"
d = BigDecimal.new(3)
f = Float(3)
time_decimal = Benchmark.measure{ (1..10000000).each { |i| d * d } }
time_float = Benchmark.measure{ (1..10000000).each { |i| f * f } }
puts time_decimal
#=> 6.770960 seconds
puts time_float
#=> 0.988070 seconds
如果您不太关心精度,请使用 float 。例如,一些科学模拟和计算仅需要3或4位有效数字。这在折衷速度准确性方面很有用。由于它们不像速度那样需要精度,因此它们会使用浮动。
如果您正在处理需要精确的数字并总结正确的数字(如复利和与金钱相关的事情),请使用十进制。请记住:如果您需要精确度,那么您应该始终使用小数。
答案 1 :(得分:17)
在Rails 3.2.18中,:decimal在使用SQLServer时变为:integer,但它在SQLite中工作正常。切换到:float为我们解决了这个问题。
吸取的教训是“始终使用同构开发和部署数据库!”
答案 2 :(得分:10)
在Rails 4.1.0中,我遇到了将纬度和经度保存到MySql数据库的问题。它不能用float数据类型保存大的分数。我将数据类型更改为十进制并为我工作。
def change change_column :cities, :latitude, :decimal, :precision => 15, :scale => 13 change_column :cities, :longitude, :decimal, :precision => 15, :scale => 13 end