Deixe-me dizer o primeiro: eu entendo completamente que os tipos de ponto flutuante não podem representar valores decimais com precisão . Não se trata disso! No entanto, os cálculos de ponto flutuante devem ser determinísticos .
Agora que isso está resolvido, deixe-me mostrar o caso curioso que observei hoje. Eu tenho uma lista de valores de ponto flutuante e quero resumi-los:
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 nós sabemos que isso 1.2
não pode ser representado exatamente em representação binária, então o resultado "impreciso" é esperado.
Agora, a seguinte coisa estranha acontece quando eu saio de 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
( sql fiddle , 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. Só consegui reproduzir esse problema com um LEFT JOIN
; INNER JOIN
funciona como esperado aqui.
Isso é inconveniente, porque significa que a DISTINCT
, GROUP BY
ou PIVOT
os vê como valores diferentes (que é realmente como descobrimos esse problema).
A solução óbvia é arredondar o valor, mas estou curioso: existe uma explicação lógica para esse comportamento?
Na verdade, o link ao qual você está se referindo não diz que os cálculos aritméticos de ponto flutuante são sempre determinísticos. De fato, em uma das respostas é mencionado que a adição não é associativa (o significado
(a + b) + c
não é necessariamente igual aa + (b + c)
), o que também é dito nesta resposta .Se a agregação de fluxo acontecer para processar linhas de cada grupo em ordem diferente -- o que o SQL Server geralmente é gratuito para fazer; se não houver nenhum
ORDER BY
na cláusula apropriada, o otimizador escolherá qualquer operador de varredura ou busca ou outro operador de consulta que seja mais rápido, independentemente da ordem em que executa as adições - isso pode explicar o comportamento observado.A adição é sempre determinística: você coloca os mesmos dois floats e obtém o mesmo float. Mas adicionar flutuadores em uma ordem diferente pode dar um resultado diferente.