Soma não determinística de carros alegóricos

10

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.2nã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 JOINfunciona como esperado aqui.

Isso é inconveniente, porque isso significa que um DISTINCT, GROUP BYou PIVOTvê-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?

Heinzi
fonte

Respostas:

15

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) + cnão é necessariamente igual a + (b + c)), o que também é dito nesta resposta .

Se a agregação de fluxo processar as linhas de cada grupo em ordem diferente - o que o SQL Server geralmente é livre para fazer; se não houver ORDER BYuma cláusula apropriada, o otimizador escolherá qualquer operador de verificação ou busca ou outro operador de consulta mais rápido, independentemente da ordem em que as adições forem executadas - isso pode explicar o comportamento observado.

A adição é sempre determinística: você coloca os mesmos dois carros alegóricos, obtém o mesmo carro alegórico. Mas adicionar flutuadores juntos em uma ordem diferente pode gerar um resultado diferente.

Ross Presser
fonte
A associatividade não tem relação com o determinismo, de modo que isso é enganoso.
Mooing Duck
A não associatividade da adição de ponto flutuante leva a um comportamento não determinístico da função agregada do SQL Server SUM(), você concorda @MooingDuck?
mustaccio 30/03/19
Não? A Divisão Inteira é um contra-exemplo claro. É não associativo, mas inteiramente determinístico. Da mesma forma, a divisão de ponto flutuante deve ser não associativa e ainda determinística. A partir disso, concluímos que é razoável que a adição seja não associativa e ainda determinística. Dito isto, se a ordem das adições não for determinística, o resultado também não será determinístico; portanto, sua primeira e última frase ainda estarão corretas, independentemente.
Mooing Duck
A divisão inteira é um contra-exemplo para o SQL Server SUM()sobre argumentos de ponto flutuante, como exatamente?
mustaccio
11
A divisão inteira é não associativa e determinística. Portanto, a associatividade das operações aritméticas não está relacionada ao determinismo. Portanto, qualquer não associatividade SUM()deve ser irrelevante em relação ao seu determinismo. Concordo que SUMparece não ser determinístico, mas você deve remover as menções de associatividade, pois isso não tem relação.
Mooing Duck