Spec-Zone .ru
спецификации, руководства, описания, API

C.5.5.8. Проблемы со Значениями С плавающей точкой

Числа с плавающей точкой иногда вызывают беспорядок, потому что они приблизительны и не сохраненные как точные значения. Значение с плавающей точкой столь же записанное в 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 на ведущем устройстве и перезагружая файл дампа в ведомое устройство, таблицы, содержащие столбцы с плавающей точкой, могли бы отличаться между двумя узлами.