Позвольте мне изложить очевидную суть: я полностью понимаю, что типы с плавающей запятой не могут точно представлять десятичные значения . Это не об этом! Тем не менее, вычисления с плавающей запятой должны быть детерминированными .
Теперь, когда это не так, позвольте мне показать вам любопытный случай, который я наблюдал сегодня. У меня есть список значений с плавающей точкой, и я хочу суммировать их:
CREATE TABLE #someFloats (val float);
INSERT INTO #someFloats (val) VALUES (1), (1), (1.2), (1.2), (1.2), (3), (5);
SELECT STR(SUM(#someFloats.val), 30, 15) FROM #someFloats;
DROP TABLE #someFloats;
-- yields:
-- 13.600000000000001
Пока все хорошо - здесь никаких сюрпризов. Мы все знаем, что 1.2не могут быть представлены точно в двоичном представлении, поэтому ожидается «неточный» результат.
Теперь, когда я покидаю другую таблицу, происходит следующая странная вещь:
CREATE TABLE #A (a int);
INSERT INTO #A (a) VALUES (1), (2);
CREATE TABLE #someFloats (val float);
INSERT INTO #someFloats (val) VALUES (1), (1), (1.2), (1.2), (1.2), (3), (5);
SELECT #A.a, STR(SUM(#someFloats.val), 30, 15)
FROM #someFloats LEFT JOIN #A ON 1 = 1
GROUP BY #A.a;
DROP TABLE #someFloats;
DROP TABLE #A;
-- yields
-- 1 13.600000000000001
-- 2 13.599999999999998
( sql fiddle , вы также можете увидеть план выполнения там)
У меня та же сумма по тем же значениям, но другая ошибка с плавающей точкой. Если я добавлю больше строк в таблицу #A, мы увидим, что значение чередуется между этими двумя значениями. Я смог воспроизвести эту проблему только с помощью LEFT JOIN; INNER JOINработает как положено здесь.
Это неудобно, потому что это означает, что DISTINCT, GROUP BYили PIVOTвидит их как разные значения (что на самом деле, как мы обнаружили эту проблему).
Очевидное решение заключается в округлении значения, но мне любопытно: есть ли логическое объяснение этому поведению?