Рельсы округляют число с плавающей точкой на уровне БД - PullRequest
3 голосов
/ 13 декабря 2011

У меня есть таблица с плавающим столбцом (я использую MySQL, mysql2 gem, все стандартно)

create_table :some_table do |t| 
  t.float  :amount 
end 

Я играл в консоли, когда я делаю

a = SomeTable.new
a.amount = 9999.99
a.save!
#9999.99
a.amount
#9999.99
a.reload
a.amount
#9999.99

все ок

a = SomeTable.new
a.amount = 9999.999
a.save!
#9999.999
a.amount 
#9999.999
a.reload
a.amount
#10000.00

когда вы видите, что рубин (или рельсы) округляет числа.

Может кто-нибудь объяснить мне, почему это? ... или только я?

Ответы [ 4 ]

2 голосов
/ 12 февраля 2014

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

Однако здесь есть более глубокая проблема.

Драйвер mysql2 не определяет точность, которую хочет вернуть mysql, поэтому база данных возвращает усеченные результаты.

Выможет заставить mysql вернуть полную точность, умножив сумму на число с плавающей запятой.

class SomeTable
  default_scope -> { select("some_tables.*, amount * 1.0000000000000000 as amount")}
end

a = SomeTable.new
a.amount = 9999.999
a.save!
#9999.999
SomeTable.last.amount 
#9999.999
SomeTable.unscoped.last.amount
#10000.00
2 голосов
/ 13 декабря 2011

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

Если вы хотите делать расчеты валюты, не используйте float! Используйте тип данных с фиксированной точкой. Если вы используете рельсовые миграции, то десятичный тип - это то, что вы хотите, как , описанное здесь .

1 голос
/ 13 декабря 2011

Документация MySQL описывает float как «приблизительный числовой тип данных» ... вероятно, не подходит для хранения денежных значений.Попробуйте вместо этого определить «количество» как десятичное .

0 голосов
/ 13 декабря 2011

Похоже, что база данных - это та, которая выполняет изменение числа.

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

...