Spec-Zone .ru
спецификации, руководства, описания, API
|
Числа с плавающей точкой иногда вызывают беспорядок, потому что они приблизительны и не сохраненные как точные
значения. Значение с плавающей точкой столь же записанное в SQL-операторе, возможно, не то же самое как
значение, представленное внутренне. Попытки обработать значения с плавающей точкой как точный в сравнениях могут
привести к проблемам. Они также подвергаются зависимостям от реализации или платформе. FLOAT
и DOUBLE
типы данных подвергаются этим проблемам. Для DECIMAL
столбцы, MySQL выполняет операции с точностью 65 десятичных цифр,
которые должны решить наиболее распространенные проблемы погрешности.
Следующее использование в качестве примера DOUBLE
демонстрировать, как вычисления, которые делаются, используя операции с
плавающей точкой, подвергаются ошибке с плавающей точкой.
mysql>CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql>INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
->(2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
->(2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
->(4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
->(5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
->(6, 0.00, 0.00), (6, -51.40, 0.00);
mysql>SELECT i, SUM(d1) AS a, SUM(d2) AS b
->FROM t1 GROUP BY i HAVING a <> b;
+------+-------+------+| i | a | b |+------+-------+------+| 1 | 21.4 | 21.4 || 2 | 76.8 | 76.8 || 3 | 7.4 | 7.4 || 4 | 15.4 | 15.4 || 5 | 7.2 | 7.2 || 6 | -51.4 | 0 |+------+-------+------+
Результат корректен. Хотя первые пять записей похожи, что они не должны удовлетворить сравнение (значения a
и b
кажись, не отличаться), они могут сделать так,
потому что различие между числами обнаруживается вокруг десятого десятичного числа или так, в зависимости от
факторов, таких как архитектура ЭВМ или версия компилятора или уровень оптимизации. Например, различные ЦП могут
оценить числа с плавающей точкой по-другому.
Если столбцы d1
и d2
был определен как DECIMAL
вместо DOUBLE
, результат SELECT
запрос содержал бы только одну строку — последний, показанный выше.
Корректный способ сделать сравнение числа с плавающей точкой состоит в том, чтобы сначала выбрать приемлемый допуск для различий между числами и затем сделать сравнение со значением допуска. Например, если мы соглашаемся, что числа с плавающей точкой должны быть расценены то же самое, если они - то же самое в пределах точности одного в десять тысяч (0.0001), сравнение должно быть записано, чтобы счесть различия больше чем значение допуска:
mysql>SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
->GROUP BY i HAVING ABS(a - b) > 0.0001;
+------+-------+------+| i | a | b |+------+-------+------+| 6 | -51.4 | 0 |+------+-------+------+1 row in set (0.00 sec)
Наоборот, чтобы получить строки, где числа являются тем же самым, тест должен найти различия в пределах значения допуска:
mysql>SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
->GROUP BY i HAVING ABS(a - b) <= 0.0001;
+------+------+------+| i | a | b |+------+------+------+| 1 | 21.4 | 21.4 || 2 | 76.8 | 76.8 || 3 | 7.4 | 7.4 || 4 | 15.4 | 15.4 || 5 | 7.2 | 7.2 |+------+------+------+5 rows in set (0.03 sec)
Значения с плавающей точкой подвергаются зависимостям от реализации или платформе. Предположите, что Вы выполняете следующие операторы:
CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0));INSERT INTO t1 VALUES('1e+52','-1e+52');SELECT * FROM t1;
На некоторых платформах, SELECT
возвраты оператора inf
и -inf
. На других это возвращается 0
и -0
.
Импликация предыдущих проблем - то, что, если Вы пытаетесь создать ведомое устройство репликации, выводя табличное содержание с mysqldump на ведущем устройстве и перезагружая файл дампа в ведомое устройство, таблицы, содержащие столбцы с плавающей точкой, могли бы отличаться между двумя узлами.