Float vs Decimal в ActiveRecord

иногда типы данных Activerecord путают меня. Часто ошибаюсь. Один из моих вечных вопросов для данного случая:--12-->

должен ли я использовать :decimal или :float?

Я часто сталкивался с этой ссылкой,ActiveRecord:: decimal vs: float?, но ответы недостаточно ясны для меня, чтобы быть уверенным:

Я видел много потоков, где люди рекомендуют никогда не использовать поплавок и всегда использовать десятичные. Я также видел предложения некоторых люди, чтобы использовать float только для научных приложений.

вот несколько примеров:

  • геолокация/широта/долгота: -45.756688, 120.5777777, ...
  • соотношение/процент: 0.9, 1.25, 1.333, 1.4143, ...

я использовал :decimal в прошлом, но я нашел дело с BigDecimal объекты в Ruby были излишне неудобными по сравнению с поплавком. Я также знаю, что я могу использовать :integer для представления денег / центов, например, но это не совсем подходит для других случаев, например, когда величины, в которых точность может меняться с течением времени.

  • каковы преимущества / недостатки использования каждого из них?
  • что бы некоторые правила, чтобы знать, какой тип использовать?

3 ответов


Я помню, мой профессор 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

ответ

использовать float когда вам все равно о точности слишком много. Например, для некоторых научных симуляций и вычислений требуется только до 3 или 4 значащих цифр. Это полезно при обмене точности на скорость. Поскольку им не нужна точность так же, как скорость, они будут использовать float.

использовать decimal если вы имеете дело с числами, которые должны быть точными и суммировать до правильного числа (например, смешивая интересы и связанные с деньгами вещи). Помните: если вам нужна точность, то вы всегда должны использовать десятичный.


в Rails 3.2.18: decimal превращается в: integer при использовании SQLServer, но он отлично работает в SQLite. Переход на: float решил эту проблему для нас.

извлеченный урок: "всегда используйте однородные базы данных разработки и развертывания!"


в Rails 4.1.0 я столкнулся с проблемой сохранения широты и долготы в базе данных MySql. Он не может сохранить большое количество фракций с типом данных float. И я меняю тип данных на decimal и работаю на меня.

  def change
    change_column :cities, :latitude, :decimal, :precision => 15, :scale => 13
    change_column :cities, :longitude, :decimal, :precision => 15, :scale => 13
  end