Float vs ActiveRecord中的十进制

有时,Activerecord数据类型会让我困惑。 呃,经常。 我的一个永恒的问题是,对于一个特定的情况,

我应该使用:decimal还是:float

我经常遇到这个链接,ActiveRecord::decimal vs:float?,但答案不够清晰,我不能确定:

我见过很多线程,人们建议平坦的时候不要使用浮点数并且总是使用小数点。 我也看到一些人建议仅将float用于科学应用。

以下是一些示例:

  • 地理位置/纬度/经度: -45.756688120.5777777 ,...
  • 比/百分比: 0.91.251.3331.4143 ,...
  • 我曾经使用过:decimal ,但是我发现在Ruby中处理BigDecimal对象与浮点数相比是不必要的尴尬。 例如,我也可以使用:integer来表示货币/美分,但它不太适合其他情况,例如,当精度可能随时间变化的数量时。

  • 使用每种方法有哪些优点/缺点?
  • 知道使用哪种类型会有什么好的经验法则?

  • 我记得我的CompSci教授说永远不要使用浮动货币。

    原因是IEEE规范以二进制格式定义浮点数。 基本上,它存储符号,分数和指数来表示浮点数。 这就像二进制的科学记数法(类似于+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
    

    回答

    当你不关心精度太多时使用浮点数 。 例如,一些科学模拟和计算只需要高达3或4位有效数字。 这对于提高速度的准确性很有用。 由于他们不需要像速度那样精确,他们会使用浮点数。

    如果您要处理的数字需要精确并加总到正确的数字(如复利兴趣和与金钱有关的东西),请使用小数 。 记住:如果你需要精确度,那么你应该总是使用小数。


    在Rails 3.2.18中,使用SQLServer时:decimal会变成:integer,但在SQLite中它工作正常。 切换到:float为我们解决了这个问题。

    吸取的教训是“始终使用同类开发和部署数据库!”


    在Rails 4.1.0中,我遇到了将纬度和经度保存到MySql数据库的问题。 它不能用浮点数据类型保存大分数。 我将数据类型更改为小数点,并为我工作。

      def change
        change_column :cities, :latitude, :decimal, :precision => 15, :scale => 13
        change_column :cities, :longitude, :decimal, :precision => 15, :scale => 13
      end
    
    链接地址: http://www.djcxy.com/p/15049.html

    上一篇: Float vs Decimal in ActiveRecord

    下一篇: Rounding Errors?