Число с плавающей запятой и десятичное в ActiveRecord - PullRequest
266 голосов
/ 15 декабря 2011

Иногда типы данных Activerecord сбивают меня с толку.ЧастоОдин из моих вечных вопросов для данного случая:

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

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

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

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

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

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

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

Ответы [ 3 ]

403 голосов
/ 15 декабря 2011

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

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

17 голосов
/ 22 октября 2014

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

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

11 голосов
/ 03 марта 2015

В 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
...