Permettez-moi de dire le poing évident: je comprends parfaitement que les types à virgule flottante ne peuvent pas représenter avec précision les valeurs décimales . Ce n'est pas ça! Néanmoins, les calculs en virgule flottante sont censés être déterministes .
Maintenant que cela est hors de propos, laissez-moi vous montrer le cas curieux que j'ai observé aujourd'hui. J'ai une liste de valeurs à virgule flottante, et je veux les résumer:
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
Jusqu'à présent, tout va bien - pas de surprise ici. Nous savons tous que cela 1.2
ne peut pas être représenté exactement en représentation binaire, donc le résultat "imprécis" est attendu.
Maintenant, la chose étrange suivante se produit lorsque je quitte une autre table:
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
( violon sql , vous pouvez également y voir le plan d'exécution)
J'ai la même somme sur les mêmes valeurs, mais une erreur à virgule flottante différente . Si j'ajoute plus de lignes au tableau #A
, nous pouvons voir que la valeur alterne entre ces deux valeurs. Je n'ai pu reproduire ce problème qu'avec un LEFT JOIN
; INNER JOIN
fonctionne comme prévu ici.
Cela n'est pas pratique, car cela signifie que a DISTINCT
, GROUP BY
ou les PIVOT
voit comme des valeurs différentes (c'est en fait ainsi que nous avons découvert ce problème).
La solution évidente est d'arrondir la valeur, mais je suis curieux: y a-t-il une explication logique à ce comportement?