Deixe-me declarar o punho óbvio: eu entendo completamente que os tipos de ponto flutuante não podem representar com precisão valores decimais . Isso não é sobre isso! No entanto, os cálculos de ponto flutuante devem ser determinísticos .
Agora que isso está fora do caminho, deixe-me mostrar o caso curioso que observei hoje. Eu tenho uma lista de valores de ponto flutuante e quero resumir:
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
Até agora, tudo bem - sem surpresas aqui. Todos sabemos que 1.2
não pode ser representado exatamente na representação binária, portanto, o resultado "impreciso" é esperado.
Agora, a seguinte coisa estranha acontece quando eu deixo entrar em outra tabela:
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
( violino sql , você também pode ver o plano de execução lá)
Eu tenho a mesma soma sobre os mesmos valores, mas um erro de ponto flutuante diferente . Se eu adicionar mais linhas à tabela #A
, podemos ver que o valor alterna entre esses dois valores. Eu só consegui reproduzir esse problema com um LEFT JOIN
; INNER JOIN
funciona como esperado aqui.
Isso é inconveniente, porque isso significa que um DISTINCT
, GROUP BY
ou PIVOT
vê-los como valores diferentes (o que é realmente como descobrimos nesta edição).
A solução óbvia é arredondar o valor, mas estou curioso: existe uma explicação lógica para esse comportamento?