Как MySQL выполняет математические вычисления сложения с плавающей точкой? - PullRequest
3 голосов
/ 23 марта 2019

Я тестировал с SELECT 0.1 + 0.2;, запросил MySQL (MariaDB), и он вернул правильный ответ

MariaDB [(none)]> SELECT 0.1 + 0.2;
+-----------+
| 0.1 + 0.2 |
+-----------+
|       0.3 |
+-----------+
1 row in set (0.000 sec)

Расчет с плавающей запятой неточен в большинстве языков программирования из-за IEEE 754 как объяснено здесь .

Как MySQL выполняет вычисление с плавающей запятой, которое возвращает правильный ответ?

Ответы [ 2 ]

5 голосов
/ 23 марта 2019

Я знаю, что SQL 92 - это старый стандарт, но я уверен, что он не изменился в более новых стандартных версиях SQL.

SQL 92 определяет

73) Подпункт 6.12, "<numeric value expression>": Когда тип данных обоих операндов сложения . вычитание, умножение, или оператор деления точное числовое значение , точность результат определяется реализацией."*

75) Подпункт 6.12, "<numeric value expression>": Когда данные тип либо операнд арифметического оператора приблизительный числовой , точность результата определяется реализацией."*

Вопрос: 0.1 и 0.2 в запросе SELECT 0.1 + 0.2 приблизительный или это точно?
Ответ: вы не знаете, база данных не может знать.
Таким образом, база данных будет запускать реализацию, определенную для движков MySQL и MariaDB, эти швы будут обрабатываться как DECIMAL(1,1) типы данных

Почему ответ Ника возвращает правильные или ожидаемые значения с определением таблицы

SQL 92 также определяет

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

Что Ник сделал, определив тип данных в таблице.

Отредактировал этот ответ, потому что сегодня я нашел кое-что в руководстве по MySQL.

Запрос

SELECT (0.1 + 0.2) = 0.3

Результат в 1 в MySQL, что означает, что MySQL использует точные числовые вычисления и использует Precision Math , где это возможно. Таким образом, MySQL знает, что 0.1, 0.2 и 0.3 являются точными типами данных и должны точно вычислять, как я ожидал до этого редактирования.

Значение запроса

SELECT (0.1 + 0.2) = 0.3 

будет работать под капотом более или менее как

SELECT CAST((0.1 + 0.2) AS DECIMAL(1, 1)) = CAST((0.3) AS DECIMAL(1, 1));
4 голосов
/ 23 марта 2019

Это просто умный MySQL в выборе типа данных / форматирования, потому что вы не указали, что эти значения являются плавающей точкой.Попробуйте это:

create table test (f float);
insert into test values (0.1), (0.2);
select sum(f) from test

Вывод:

sum(f)
0.30000000447034836

Демонстрация на dbfiddle

Если вы используете двойную точность, вы получите классический 0.30000000000000004результат. Демонстрация на dbfiddle

...