Biarkan saya menyatakan tinju yang jelas: Saya benar-benar mengerti bahwa tipe floating point tidak dapat secara akurat mewakili nilai desimal . Ini bukan tentang itu! Namun demikian, perhitungan floating point seharusnya bersifat deterministik .
Sekarang ini sudah keluar dari jalan, izinkan saya menunjukkan kepada Anda kasus aneh yang saya amati hari ini. Saya memiliki daftar nilai floating-point, dan saya ingin merangkumnya:
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
Sejauh ini, sangat bagus - tidak ada kejutan di sini. Kita semua tahu bahwa 1.2
tidak dapat direpresentasikan secara tepat dalam representasi biner, sehingga hasil "tidak tepat" diharapkan.
Sekarang hal aneh berikut terjadi ketika saya pergi-bergabung dengan meja lain:
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 biola , Anda juga dapat melihat rencana eksekusi di sana)
Saya memiliki jumlah yang sama di atas nilai yang sama , tetapi kesalahan floating-point yang berbeda . Jika saya menambahkan lebih banyak baris ke tabel #A
, kita dapat melihat bahwa nilainya berganti antara dua nilai tersebut. Saya hanya dapat mereproduksi masalah ini dengan LEFT JOIN
; INNER JOIN
berfungsi seperti yang diharapkan di sini.
Ini tidak nyaman, karena itu berarti bahwa DISTINCT
, GROUP BY
atau PIVOT
melihatnya sebagai nilai yang berbeda (yang sebenarnya adalah bagaimana kami menemukan masalah ini).
Solusi yang jelas adalah untuk membulatkan nilainya, tetapi saya ingin tahu: Apakah ada penjelasan logis untuk perilaku ini?
sumber
SUM()
, apakah Anda setuju @MooingDuck?SUM()
atas argumen floating point, bagaimana tepatnya?SUM()
harus tidak relevan dengan determinisme itu. Saya setuju bahwaSUM
tampaknya tidak deterministik, tetapi Anda harus menghapus menyebutkan asosiatif, karena itu tidak berhubungan.