Позвольте мне изложить очевидную суть: я полностью понимаю, что типы с плавающей запятой не могут точно представлять десятичные значения . Это не об этом! Тем не менее, вычисления с плавающей запятой должны быть детерминированными .
Теперь, когда это не так, позвольте мне показать вам любопытный случай, который я наблюдал сегодня. У меня есть список значений с плавающей точкой, и я хочу суммировать их:
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
видит их как разные значения (что на самом деле, как мы обнаружили эту проблему).
Очевидное решение заключается в округлении значения, но мне любопытно: есть ли логическое объяснение этому поведению?