Eşitlik için kayan nokta değerleri karşılaştırılırken iki farklı yaklaşım vardır:
NaN
IEEE 754 şartnamesine uyan kendine eşit olmamalıdır .NaN
Eşdeğerlik ilişkisinin tanımlanması için gerekli olan refleksivitenin matematiksel özelliğini sağlayan kendisine eşit olmak
C # ( float
ve double
) içindeki yerleşik IEEE kayan nokta türleri ve ==
ve !=
(ve ilişkisel operatörler gibi <
) için IEEE semantiğini takip eder, ancak object.Equals
, IEquatable<T>.Equals
(ve CompareTo
) için yansıma sağlar .
Şimdi float
/ üstünde vektör yapılar sağlayan bir kütüphane düşünün double
. Böyle bir vektör tipi aşırı yüklenir ==
/ !=
ve geçersiz kılınır object.Equals
/ IEquatable<T>.Equals
.
Herkesin kabul ettiği şey, IEEE anlambilimine uymak ==
/ !=
uymaktır. Soru, böyle bir kütüphanenin Equals
yöntemi (eşitlik operatörlerinden ayrı olarak) refleksif veya IEEE anlambilimine uygun bir şekilde uygulamasıdır.
IEEE semantiğini aşağıdakiler için kullanmak için bağımsız değişkenler Equals
:
- IEEE 754'ü takip ediyor
SIMD talimatlarından yararlanabileceğinden (muhtemelen çok daha hızlı)
Stackoverflow hakkında, SIMD talimatlarını ve performans etkilerini kullanarak refleksif eşitliği nasıl ifade edeceğiniz hakkında ayrı bir soru sordum: Kayan nokta eşitliği karşılaştırması için SIMD talimatları
Güncelleme: Üç SIMD talimatını kullanarak refleksif eşitliği etkili bir şekilde uygulamak mümkün görünmektedir.
İçin dokümantasyon
Equals
, kayan noktayı dahil ederken refleksivite gerektirmez:Aşağıdaki ifadeler, Equals (Object) yönteminin tüm uygulamaları için doğru olmalıdır. Listede,
x
,y
vez
boş olmayan nesne referanslarını temsil eder.x.Equals(x)
true
kayan noktalı türleri içeren durumlar dışında döner . Bkz. ISO / IEC / IEEE 60559: 2011, Bilgi teknolojisi - Mikroişlemci Sistemleri - Kayan Nokta aritmetiği.Sözlük anahtarı olarak şamandıralar kullanıyorsanız, günah durumunda yaşıyorsunuz ve aklı başında davranış beklememelisiniz.
Dönüşlü olma argümanları:
Bu da dahil olmak üzere, mevcut tipleri, uyuyor
Single
,Double
,Tuple
veSystem.Numerics.Complex
.BCL'de
Equals
refleksif olmak yerine IEEE'yi takip eden herhangi bir örnek bilmiyorum . Sayaç örneklerSingle
,Double
,Tuple
veSystem.Numerics.Complex
.Equals
çoğunlukla refleksiviteye dayanan kapsayıcılar ve arama algoritmaları tarafından kullanılır. Bu algoritmalar için, bir performans kazancı, çalışmalarını önlüyorsa önemsizdir. Performans için doğruluktan ödün vermeyin.- Tüm karma tabanlı setleri ve sözlükleri kırar,
Contains
,Find
,IndexOf
çeşitli koleksiyonlardan / LINQ set bazlı LINQ operasyonları (üzerindeUnion
,Except
vs.) veri içeriyorsaNaN
değerlerini. IEEE semantiğinin kabul edilebilir olduğu gerçek hesaplamaları yapan kod genellikle somut türler üzerinde çalışır ve
==
/!=
(veya daha olası epsilon karşılaştırmaları) kullanır.Bunun için aritmetik işlemlere ihtiyaç duyduğunuzdan, şu anda jenerikler kullanarak yüksek performanslı hesaplamalar yazamazsınız, ancak bunlar arayüzler / sanal yöntemler aracılığıyla kullanılamaz.
Bu nedenle, daha yavaş bir
Equals
yöntem çoğu yüksek performans kodunu etkilemez.IEEE semantiğine veya performans avantajına ihtiyaç duyduğunuz durumlarda bir
IeeeEquals
yöntem veya bir sağlamak mümkündürIeeeEqualityComparer<T>
.
Kanımca bu argümanlar dönüşlü bir uygulamayı kuvvetle desteklemektedir.
Microsoft'un CoreFX ekibi böyle bir vektör türünü .NET'e tanıtmayı planlıyor. Benden farklı olarak , temel olarak performans avantajları nedeniyle IEEE çözümünü tercih ediyorlar . Son bir sürümden sonra böyle bir karar kesinlikle değiştirilmeyeceğinden, büyük bir hata olduğuna inandığım şeyden topluluktan geri bildirim almak istiyorum.
float
/ double
ve diğer bazı türler için ==
ve Equals
zaten farklı. Mevcut türlerle tutarsızlığın, aralarındaki tutarsızlıktan daha da kafa karıştırıcı olacağını düşünüyorum ==
ve Equals
yine de diğer türlerle uğraşmak zorunda kalacaksınız. 2) Hemen hemen tüm jenerik algoritmalar / koleksiyonlar Equals
işlevini (LINQ ve sözlükler) kullanırlar ve somut kayan nokta algoritmaları tipik olarak ==
IEEE semantiklerini aldıkları yerde kullanırlar .
Vector<float>
basit float
ya da farklı bir "canavar" düşünün double
. Bu önlemle, operatörün standartlarına uyma nedenini Equals
veya ==
operatörünü göremiyorum . Kendinizi dediniz: "Eğer sözlük anahtarları olarak kayan nokta kullanıyorsanız, günah durumunda yaşıyorsunuz ve aklı başında davranış beklememelisiniz". Biri NaN
sözlükte saklanacak olsaydı , o zaman korkunç bir uygulama kullanmak kendi kahrolası hatasıdır. CoreFX ekibinin bunu düşünmediğini pek düşünmüyorum. ReflexiveEquals
Sadece performans uğruna bir veya benzeri ile giderdim .
==
veEquals
farklı sonuçlar getirecekti. Birçok programcı olduklarını varsayalım ve bunu aynı şeyi . Ayrıca - genel olarak, eşitlik operatörlerinin uygulamalarıEquals
yöntemi çağırmaktadır . Birinin bir içerebileceğini iddia ettinizIeeeEquals
, ancak biri bunu başka şekilde de yapabilir ve bir-ReflexiveEquals
yöntem içerebilir .Vector<float>
-Tipi kullanılabilen çok performans açısından kritik uygulamalar ve buna göre optimize edilmelidir.