проблемы с обработкой значащих цифр в mysql, конвертирующих float в double - PullRequest
0 голосов
/ 29 сентября 2018

Я вставляю данные из одной таблицы в другую в базе данных MariaDB, где столбец в первой таблице равен FLOAT, а во второй - DOUBLE.Данные могут иметь значения любого размера, точности и десятичного разряда.

Вот что происходит со значениями, когда я делаю прямое копирование:

INSERT INTO data2 (value) SELECT value FROM data1

Значения задаются случайнымидополнительные значащие цифры:

FLOAT in data1           DOUBLE in data2
-0.000000000000454747    -0.0000000000004547473508864641
-122.319                 -122.31932830810547
14864199700              14864220160

CAST(value AS DECIMAL(65,30)) генерирует точно такие же значения, что и столбец 2 выше, за исключением того, что я вижу конечные нули.

Тем не менее, когда я просто делаю

UPDATE data2 SET value = 14867199700 WHERE id = 133025046;

значение DOUBLE принято.

Нужно ли экспортировать все значения в сценарий SQL и повторно импортировать их?Нет ли лучшего способа?

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

1 Ответ

0 голосов
/ 11 октября 2018

Ваш тестовый пример имеет недостатки.Вы вводите десятичные цифры и не тестируете просто . Передача FLOAT в DOUBLE.

UPDATE tbl SET double_col = float_col всегда копирует одно и то же значение.Это потому, что представление DOUBLE является расширенным набором представления FLOAT (53 против 24 бит точности; и т. Д.).

Литерал с десятичными знаками: UPDATE tbl SET double_col = 123.456 будет искажать число из-за округления отдесятичное число до DOUBLE.То же самое для float_col.Кроме того, искаженные результаты будут другими!

Литерал номера отверстия: UPDATE tbl SET double_col = 14867199700 будет сохранен точно.Но если вы поместите тот же самый литерал в FLOAT, он будет округлен до 24 бит, поэтому он не может быть сохранен точно.Вы теряете точность на о 7 значащих цифрах для FLOAT и о 16 для DOUBLE.Литерал в этом примере имеет 9 значащих цифр (после игнорирования конечных нулей).

Это просто пример кошмаров, в которые вы можете попасть.

Вы должны рассмотреть FLOAT и DOUBLE должны быть приблизительными .Вы никогда не должны сравнивать на равенство;вы не знаете, что могло быть с последним битом значения.

Кроме того, вы не должны пытаться угадать, когда MySQL будет выполнять выражения в DECIMAL вместо DOUBLE.

И имейте в виду, что деление обычно неточное из-за округления до некоторого числа бит или десятичных дробей.

"Мантисса" 14864199700 равна

    1.10111010111111001101100 (binary of FLOAT : 24 bits including 'hidden' leading bit)
    1.1011101011111100110110000000101000000000000000000000 (binary of DOUBLE)
                                  ^ ^  (lost in FLOAT)

Каждое из них умножаетсяпри той же степени 2. DOUBLE получает ровно 14864199700. FLOAT потерял указанные биты.

Вы можете поиграть с такими при https://gregstoll.dyndns.org/~gregstoll/floattohex/

Верьте илинет, раньше было хуже.Люди будут платить за 0,00 долларов из-за ошибок округления.Или результаты того, что должно было быть 1 + 1, показали как 1.99999999.

...