Somma non deterministica di galleggianti


10

Consentitemi di esprimere il pugno ovvio: capisco perfettamente che i tipi in virgola mobile non possono rappresentare con precisione i valori decimali . Non si tratta di questo! Tuttavia, i calcoli in virgola mobile dovrebbero essere deterministici .

Ora che questo è fuori mano, lascia che ti mostri il caso curioso che ho osservato oggi. Ho un elenco di valori in virgola mobile e voglio riassumerli:

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

Fin qui tutto bene - nessuna sorpresa qui. Sappiamo tutti che 1.2non può essere rappresentato esattamente nella rappresentazione binaria, quindi ci si aspetta il risultato "impreciso".

Ora succede la seguente cosa strana quando mi unisco a sinistra per un altro tavolo:

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 , puoi anche vedere il piano di esecuzione lì)

Ho la stessa somma sugli stessi valori, ma un diverso errore in virgola mobile. Se aggiungo più righe alla tabella #A, possiamo vedere che il valore si alterna tra questi due valori. Sono stato in grado di riprodurre questo problema solo con un LEFT JOIN; INNER JOINfunziona come previsto qui.

Questo è scomodo, perché significa che a DISTINCT, GROUP BYo PIVOTli vede come valori diversi (che è in realtà il modo in cui abbiamo scoperto questo problema).

La soluzione ovvia è arrotondare il valore, ma sono curioso: esiste una spiegazione logica per questo comportamento?

Risposte:


15

In realtà, il collegamento a cui ti riferisci non dice che i calcoli aritmetici in virgola mobile sono sempre deterministici. In effetti, in una delle risposte è menzionato che l'addizione non è associativa (il significato (a + b) + cnon è necessariamente uguale a + (b + c)), come indicato anche in questa risposta .

Se l'aggregazione dei flussi si verifica per elaborare le righe di ciascun gruppo in un ordine diverso, cosa che normalmente SQL Server è libero di fare; se non è presente ORDER BYnella clausola appropriata, l'ottimizzatore sceglierà qualunque scansione o ricerca o un altro operatore di query sarà più veloce, indipendentemente dall'ordine in cui vengono eseguite le aggiunte, quindi ciò potrebbe spiegare il comportamento che si osserva.

L'aggiunta è sempre deterministica: si inseriscono gli stessi due float, si ottiene lo stesso float. Ma l'aggiunta di float insieme in un ordine diverso può dare un risultato diverso.


L'associatività non ha alcuna relazione con il determinismo, quindi quel bit è fuorviante.
Mooing Duck,

La non associatività dell'aggiunta in virgola mobile porta a un comportamento non deterministico della funzione aggregata di SQL Server SUM(), concorderesti con @MooingDuck?
Mustaccio,

No? La divisione Integer è un chiaro controesempio. È non associativo, ma del tutto deterministico. Allo stesso modo, la divisione in virgola mobile dovrebbe essere non associativa e comunque deterministica. Da ciò, concludiamo che è ragionevole che l'aggiunta sia non associativa e ancora deterministica. Detto questo, se l'ordine delle aggiunte non è deterministico, anche il risultato non sarà deterministico, quindi la tua prima e ultima frase sono comunque corrette indipendentemente.
Mooing Duck,

La divisione dei numeri interi è un controesempio per SQL Server SUM()su argomenti in virgola mobile, come esattamente?
Mustaccio,

1
La divisione intera è non associativa e deterministica. Pertanto, l'associatività delle operazioni aritmetiche non è correlata al determinismo. Pertanto qualsiasi non associatività di SUM()deve essere irrilevante per il suo determinismo. Sono d'accordo che SUMsembra non essere deterministico, ma dovresti rimuovere le menzioni di associatività, dal momento che non è correlato.
Mooing Duck
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.