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.2nie 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 JOINdziała zgodnie z oczekiwaniami tutaj.
Jest to niewygodne, ponieważ oznacza to, że DISTINCT, GROUP BYczy PIVOTwidzi 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?