Saat membandingkan nilai floating point untuk kesetaraan, ada dua pendekatan berbeda:
NaN
tidak sama dengan dirinya sendiri, yang cocok dengan spesifikasi IEEE 754 .NaN
menjadi sama dengan dirinya sendiri, yang menyediakan properti matematika dari Refleksivitas yang penting untuk definisi relasi Kesetaraan
Tipe floating point IEEE bawaan di C # ( float
dan double
) mengikuti semantik IEEE untuk ==
dan !=
(dan operator relasional suka <
) tetapi memastikan refleksivitas untuk object.Equals
, IEquatable<T>.Equals
(dan CompareTo
).
Sekarang pertimbangkan perpustakaan yang menyediakan struct vektor di atas float
/ double
. Jenis vektor seperti itu akan membebani ==
/ !=
dan menimpa object.Equals
/ IEquatable<T>.Equals
.
Apa yang semua orang setuju pada adalah bahwa ==
/ !=
harus mengikuti IEEE semantik. Pertanyaannya adalah, haruskah perpustakaan seperti itu menerapkan Equals
metode (yang terpisah dari operator kesetaraan) dengan cara yang refleksif atau dengan cara yang cocok dengan semantik IEEE.
Argumen untuk menggunakan semantik IEEE untuk Equals
:
- Ini mengikuti IEEE 754
Ini (mungkin jauh lebih cepat) karena dapat memanfaatkan instruksi SIMD
Saya telah mengajukan pertanyaan terpisah tentang stackoverflow tentang bagaimana Anda akan mengekspresikan kesetaraan refleksif menggunakan instruksi SIMD dan dampak kinerjanya: Instruksi SIMD untuk perbandingan kesetaraan floating point
Pembaruan: Sepertinya mungkin untuk menerapkan kesetaraan refleksif secara efisien menggunakan tiga instruksi SIMD.
Dokumentasi untuk
Equals
tidak memerlukan refleksivitas ketika melibatkan floating point:Pernyataan berikut harus benar untuk semua implementasi metode Persamaan (Objek). Dalam daftar,
x
,y
, danz
mewakili referensi objek yang tidak nol.x.Equals(x)
kembalitrue
, kecuali dalam kasus yang melibatkan tipe floating-point. Lihat ISO / IEC / IEEE 60559: 2011, Teknologi informasi - Sistem Mikroprosesor - Aritmatika Titik Apung.Jika Anda menggunakan pelampung sebagai kunci kamus, Anda hidup dalam keadaan berdosa dan seharusnya tidak mengharapkan perilaku waras.
Argumen untuk bersikap refleksif:
Ini konsisten dengan jenis yang ada, termasuk
Single
,Double
,Tuple
danSystem.Numerics.Complex
.Saya tidak tahu preseden apa pun di BCL tempat
Equals
mengikuti IEEE bukannya refleksif. Contoh kontra termasukSingle
,Double
,Tuple
danSystem.Numerics.Complex
.Equals
sebagian besar digunakan oleh wadah dan algoritma pencarian yang bergantung pada refleksivitas. Untuk algoritme ini, peningkatan kinerja tidak relevan jika mencegahnya bekerja. Jangan mengorbankan kebenaran untuk kinerja.- Rusak semua set berdasarkan hash dan kamus,
Contains
,Find
,IndexOf
pada berbagai koleksi / LINQ, operasi ditetapkan berdasarkan LINQ (Union
,Except
, dll) jika data yang berisiNaN
nilai-nilai. Kode yang melakukan perhitungan aktual di mana semantik IEEE dapat diterima biasanya bekerja pada tipe dan penggunaan konkret
==
/!=
(atau lebih mungkin perbandingan epsilon).Saat ini Anda tidak dapat menulis perhitungan kinerja tinggi menggunakan generik karena Anda memerlukan operasi aritmatika untuk itu, tetapi ini tidak tersedia melalui antarmuka / metode virtual.
Jadi
Equals
metode yang lebih lambat tidak akan memengaruhi kode kinerja paling tinggi.Dimungkinkan untuk memberikan
IeeeEquals
metode atauIeeeEqualityComparer<T>
untuk kasus di mana Anda membutuhkan semantik IEEE atau Anda perlu untuk keuntungan kinerja.
Menurut pendapat saya argumen ini sangat mendukung implementasi refleksif.
Tim CoreFX Microsoft berencana untuk memperkenalkan tipe vektor seperti itu dalam .NET. Tidak seperti saya, mereka lebih suka solusi IEEE , terutama karena keunggulan kinerja. Karena keputusan seperti itu tentu tidak akan berubah setelah rilis final, saya ingin mendapatkan umpan balik dari masyarakat, tentang apa yang saya yakini sebagai kesalahan besar.
float
/ double
dan beberapa jenis lainnya, ==
dan Equals
sudah berbeda. Saya pikir ketidakkonsistenan dengan tipe yang ada akan lebih membingungkan daripada ketidakkonsistenan di antara keduanya ==
dan Equals
Anda masih harus berurusan dengan tipe yang lain. 2) Hampir semua algoritma / koleksi generik digunakan Equals
dan bergantung pada refleksifitasnya untuk berfungsi (LINQ dan kamus), sedangkan algoritma floating-point konkret biasanya digunakan di ==
mana mereka mendapatkan semantik IEEE mereka.
Vector<float>
"binatang" yang berbeda dari yang sederhana float
atau double
. Dengan ukuran itu, saya tidak bisa melihat alasan Equals
atau ==
operator untuk mematuhi standar mereka. Anda berkata sendiri: "Jika Anda menggunakan pelampung sebagai kunci kamus, Anda hidup dalam keadaan berdosa dan seharusnya tidak mengharapkan perilaku waras". Jika seseorang menyimpan NaN
dalam kamus, maka itu adalah kesalahan mereka sendiri karena menggunakan latihan yang mengerikan. Saya hampir tidak berpikir bahwa tim CoreFX tidak memikirkan hal ini. Saya akan pergi dengan ReflexiveEquals
atau serupa, hanya demi kinerja.
==
danEquals
akan memberikan hasil yang berbeda. Banyak programmer berasumsi, dan melakukan hal yang sama . Selanjutnya - secara umum, implementasi dari operator kesetaraan memohonEquals
metode. Anda berpendapat bahwa seseorang dapat memasukkan aIeeeEquals
, tetapi orang mungkin juga melakukannya sebaliknya dan memasukkanReflexiveEquals
-metode. TheVector<float>
-jenis dapat digunakan dalam banyak aplikasi kinerja-kritis, dan harus dioptimalkan sesuai.