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.
sumber
==
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.float
/double
dan beberapa jenis lainnya,==
danEquals
sudah berbeda. Saya pikir ketidakkonsistenan dengan tipe yang ada akan lebih membingungkan daripada ketidakkonsistenan di antara keduanya==
danEquals
Anda masih harus berurusan dengan tipe yang lain. 2) Hampir semua algoritma / koleksi generik digunakanEquals
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 sederhanafloat
ataudouble
. Dengan ukuran itu, saya tidak bisa melihat alasanEquals
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 menyimpanNaN
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 denganReflexiveEquals
atau serupa, hanya demi kinerja.Jawaban:
Saya berpendapat bahwa perilaku IEEE benar.
NaN
s tidak setara satu sama lain dengan cara apa pun; mereka sesuai dengan kondisi yang tidak jelas di mana jawaban numerik tidak sesuai.Di luar manfaat kinerja yang berasal dari penggunaan aritmatika IEEE yang didukung sebagian besar prosesor secara bawaan, saya pikir ada masalah semantik dengan mengatakan bahwa jika
isnan(x) && isnan(y)
, makax == y
. Contohnya:Saya berpendapat bahwa tidak ada alasan yang berarti mengapa seseorang dianggap
x
setaray
. Anda hampir tidak dapat menyimpulkan bahwa mereka adalah angka yang setara; mereka sama sekali bukan angka, jadi sepertinya konsep yang sama sekali tidak valid.Selain itu, dari perspektif desain API, jika Anda bekerja pada pustaka serba guna yang dimaksudkan untuk digunakan oleh banyak pemrogram, masuk akal untuk menggunakan semantik titik-mengambang yang paling khas industri. Tujuan perpustakaan yang baik adalah untuk menghemat waktu bagi mereka yang menggunakannya, sehingga membangun perilaku yang tidak standar sudah matang untuk kebingungan.
sumber
NaN == NaN
seharusnya mengembalikan false tidak perlu dipersoalkan lagi. Pertanyaannya adalah apa yang.Equals
harus dilakukan metode ini. Misalnya jika saya gunakanNaN
sebagai kunci kamus, nilai yang terkait menjadi tidak dapat dikembalikan jikaNaN.Equals(NaN)
kembali salah.Single
,Double
, dll kelas sudah memiliki perilaku refleksif. IMHO, itu hanya keputusan yang salah untuk memulai. Tapi saya tidak akan membiarkan keanggunan menghalangi kegunaan / kecepatan.==
yang selalu mengikuti IEEE, sehingga mereka akan mendapatkan kode cepat tidak peduli bagaimanaEquals
penerapannya. IMO seluruh titik memilikiEquals
metode terpisah digunakan dalam algoritma yang tidak peduli tentang jenis beton, sepertiDistinct()
fungsi LINQ .==
operator danEquals()
fungsi yang memiliki semantik berbeda. Saya pikir Anda membayar biaya kebingungan potensial dari perspektif pengembang, tanpa manfaat nyata (saya tidak menetapkan nilai apa pun untuk dapat menggunakan vektor angka sebagai kunci kamus). Itu hanya pendapat saya; Saya tidak berpikir ada jawaban obyektif untuk pertanyaan yang ada.Ada masalah: IEEE754 mendefinisikan operasi relasional dan kesetaraan dengan cara yang cocok untuk aplikasi numerik. Tidak cocok untuk menyortir dan hashing. Jadi jika Anda ingin mengurutkan array berdasarkan nilai numerik, atau jika Anda ingin menambahkan nilai numerik ke set atau menggunakannya sebagai kunci dalam kamus, Anda juga menyatakan bahwa nilai NaN tidak diperbolehkan, atau Anda tidak menggunakan IEEE754 operasi bawaan. Tabel hash Anda harus memastikan bahwa semua NaN dicocokkan dengan nilai yang sama, dan membandingkan sama satu sama lain.
Jika Anda mendefinisikan Vector maka Anda harus membuat keputusan desain apakah Anda ingin menggunakannya hanya untuk tujuan numerik atau apakah itu harus kompatibel dengan pengurutan dan hashing. Saya pribadi berpikir bahwa tujuan numerik harusnya jauh lebih penting. Jika pengurutan / hashing diperlukan maka Anda dapat menulis kelas dengan Vector sebagai anggota dan mendefinisikan hashing dan kesetaraan di kelas itu seperti yang Anda suka.
sumber
==
dan!=
operator untuk mereka. Dalam pengalaman sayaEquals
metode ini cukup banyak hanya digunakan oleh algoritma non numerik.