Pozwól mi powiedzieć oczywistą pięść: całkowicie rozumiem, że typy zmiennoprzecinkowe nie mogą dokładnie reprezentować wartości dziesiętnych . Tu nie chodzi o to! Niemniej jednak obliczenia zmiennoprzecinkowe mają być deterministyczne .
Teraz, gdy to już nie przeszkadza, pokażę ci ciekawy przypadek, który obserwowałem dzisiaj. Mam listę wartości zmiennoprzecinkowych i chcę je podsumować:
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
Jak dotąd tak dobrze - nie ma tu niespodzianek. Wszyscy wiemy, że 1.2
nie można tego dokładnie przedstawić w reprezentacji binarnej, więc oczekuje się „nieprecyzyjnego” wyniku.
Teraz, gdy opuszczam inny stolik, dzieje się następująca dziwna rzecz:
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
( skrzypce sql , możesz tam również zobaczyć plan wykonania)
Mam tę samą sumę dla tych samych wartości, ale inny błąd zmiennoprzecinkowy. Jeśli dodam więcej wierszy do tabeli #A
, możemy zobaczyć, że wartość zmienia się między tymi dwiema wartościami. Byłem w stanie odtworzyć ten problem tylko z LEFT JOIN
; INNER JOIN
działa zgodnie z oczekiwaniami tutaj.
Jest to niewygodne, ponieważ oznacza to, że DISTINCT
, GROUP BY
czy PIVOT
widzi je jako różne wartości (co jest faktycznie jak odkryliśmy ten problem).
Oczywistym rozwiązaniem jest zaokrąglenie wartości, ale jestem ciekawy: czy istnieje logiczne wytłumaczenie tego zachowania?