Проблемы точности Mysql с плавающей точкой в ​​Rails - PullRequest
3 голосов
/ 15 августа 2011

Для моего текущего проекта мне пришлось перепроектировать нашу старую базу данных и сохранить все старые данные. Я написал задачу rake для копирования всех данных (это не прямое сопоставление один к одному), который работает нормально, за исключением нескольких значений с плавающей запятой.

Некоторые значения определены как значения с плавающей точкой в ​​старой базе данных Mysql. Проблема в том, что мои запросы ActiveRecord возвращают округленное значение вместо фактического значения. Если я запускаю запрос к старой базе данных, я получаю:

mysql> select mean, format(mean, 10) from example_table;
+---------+------------------+
| mean    | format(mean, 10) |
+---------+------------------+
| 1.10844 | 1.1084357500     |
| 1.10223 | 1.1022269726     |
| 1.11771 | 1.1177104712     |
+---------+------------------+

Фактические значения среднего значения соответствуют форматированному значению MOST времени. Иногда некоторые значения имеют меньше значащих цифр, и format(mean, 10) будет предоставлять неправильные цифры (например, 1.1 даст что-то вроде 1.1000001421).

В моей задаче о граблях я запрашиваю старую базу данных:

values = ActiveRecord::Base.connection.execute('SELECT mean FROM example_table')

К сожалению, values будет содержать это округленное значение вместо фактического значения. Есть ли способ получить действительное значение вместо округленного значения?

Я использую Mysql Distrib 5.1.51 и Rails 3.0.9

Пояснение:

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

values = ActiveRecord::Base.connection.execute('SELECT mean FROM example_table') #selects from the legacy database

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

Другими словами, когда я запрашиваю mysql, я хочу, чтобы он вернул точное значение, которое было вставлено. Это могло быть 1.0 или 1.23456789. Мне все равно, сколько значащих цифр, я просто хочу это точное значение.

Где-то между выполнением оператора select и AR, возвращающим значения, значения округляются. Я пытаюсь понять, где эта точка.

Ответы [ 2 ]

3 голосов
/ 03 октября 2011

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

def self.up
    change_column :revenues, :amount, :decimal, :precision => 12, :scale => 2
end

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

0 голосов
/ 03 октября 2011

Это объясняет, почему вы НИКОГДА не должны использовать плавающую точку для точности - плавающая для величин.

Если нужно измерить расстояние до Луны в световых годах - у них будет деление, но если вы используете миллиметры в качестве целого числа, вы получите очень точное число - верно?

http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html

Причина, по которой дроби между деци и гекса не могут быть преобразованы точно.

Когда я делаю XML, я использую атрибут, содержащий количество фракций (делитель), когда выполняю вычисления высокой точности - например, value = "123456789" divisor = "1000" - это обеспечивает плавную обработку различных слоев без потери чего-либо ...

В MySQL я не хочу столбцов - поэтому десятичные представления, это ваш ответ ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...