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.2
non 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 JOIN
funziona come previsto qui.
Questo è scomodo, perché significa che a DISTINCT
, GROUP BY
o PIVOT
li 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?