Saat membandingkan nilai floating point untuk kesetaraan, ada dua pendekatan berbeda:
NaNtidak sama dengan dirinya sendiri, yang cocok dengan spesifikasi IEEE 754 .NaNmenjadi sama dengan dirinya sendiri, yang menyediakan properti matematika dari Refleksivitas yang penting untuk definisi relasi Kesetaraan
Tipe floating point IEEE bawaan di C # ( floatdan 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 Equalsmetode (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
Equalstidak memerlukan refleksivitas ketika melibatkan floating point:Pernyataan berikut harus benar untuk semua implementasi metode Persamaan (Objek). Dalam daftar,
x,y, danzmewakili 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,TupledanSystem.Numerics.Complex.Saya tidak tahu preseden apa pun di BCL tempat
Equalsmengikuti IEEE bukannya refleksif. Contoh kontra termasukSingle,Double,TupledanSystem.Numerics.Complex.Equalssebagian 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,IndexOfpada berbagai koleksi / LINQ, operasi ditetapkan berdasarkan LINQ (Union,Except, dll) jika data yang berisiNaNnilai-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
Equalsmetode yang lebih lambat tidak akan memengaruhi kode kinerja paling tinggi.Dimungkinkan untuk memberikan
IeeeEqualsmetode 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/ doubledan beberapa jenis lainnya, ==dan Equalssudah berbeda. Saya pikir ketidakkonsistenan dengan tipe yang ada akan lebih membingungkan daripada ketidakkonsistenan di antara keduanya ==dan EqualsAnda masih harus berurusan dengan tipe yang lain. 2) Hampir semua algoritma / koleksi generik digunakan Equalsdan 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 floatatau double. Dengan ukuran itu, saya tidak bisa melihat alasan Equalsatau ==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 NaNdalam 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 ReflexiveEqualsatau serupa, hanya demi kinerja.
==danEqualsakan memberikan hasil yang berbeda. Banyak programmer berasumsi, dan melakukan hal yang sama . Selanjutnya - secara umum, implementasi dari operator kesetaraan memohonEqualsmetode. 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.