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?
fonte
SUM()
, você concorda @MooingDuck?SUM()
sobre argumentos de ponto flutuante, como exatamente?SUM()
deve ser irrelevante em relação ao seu determinismo. Concordo queSUM
parece não ser determinístico, mas você deve remover as menções de associatividade, pois isso não tem relação.