Jumlah pelampung non-deterministik

10

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.2tidak 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 JOINberfungsi seperti yang diharapkan di sini.

Ini tidak nyaman, karena itu berarti bahwa DISTINCT, GROUP BYatau PIVOTmelihatnya 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?

Heinzi
sumber

Jawaban:

15

Sebenarnya, tautan yang Anda maksud tidak mengatakan bahwa perhitungan aritmatika floating point selalu deterministik. Bahkan, dalam salah satu jawaban disebutkan bahwa penambahan tidak asosiatif (artinya (a + b) + ctidak harus sama a + (b + c)), yang juga dikatakan dalam jawaban ini .

Jika aliran agregasi terjadi untuk memproses baris dari masing-masing kelompok dalam urutan yang berbeda - yang biasanya dilakukan SQL Server; jika tidak ada ORDER BYdalam klausa yang sesuai, maka pengoptimal akan memilih pemindaian atau pencarian apa pun atau operator permintaan lainnya akan menjadi tercepat, terlepas dari urutan apa yang melakukan penambahan - maka ini dapat menjelaskan perilaku yang Anda amati.

Penambahan selalu deterministik: Anda memasukkan dua float yang sama, Anda mendapatkan float yang sama. Tetapi menambahkan pelampung bersama dalam urutan yang berbeda dapat memberikan hasil yang berbeda.

Ross Presser
sumber
Asosiatif tidak memiliki hubungan dengan determinisme, sehingga bit itu menyesatkan.
Mooing Duck
Non-associativity penambahan floating point mengarah ke perilaku non-deterministik fungsi agregat SQL Server SUM(), apakah Anda setuju @MooingDuck?
mustaccio
Tidak? Divisi Integer adalah contoh tandingan yang jelas. Ini non-asosiatif, tetapi sepenuhnya deterministik. Demikian juga, pembagian floating point harus non-asosiatif dan masih deterministik. Dari itu, kami menyimpulkan bahwa masuk akal untuk menjadi non-asosiatif dan masih deterministik. Yang sedang berkata, jika urutan penambahan tidak deterministik, maka hasilnya juga tidak akan deterministik, sehingga kalimat pertama dan terakhir Anda tetap benar.
Mooing Duck
Divisi integer adalah contoh tandingan untuk SQL Server SUM()atas argumen floating point, bagaimana tepatnya?
mustaccio
1
Divisi integer adalah non-asosiatif dan deterministik. Oleh karena itu, asosiatif operasi aritmatika tidak terkait dengan determinisme. Oleh karena itu setiap non-asosiasi dari SUM()harus tidak relevan dengan determinisme itu. Saya setuju bahwa SUMtampaknya tidak deterministik, tetapi Anda harus menghapus menyebutkan asosiatif, karena itu tidak berhubungan.
Mooing Duck