Eşitlik için kayan nokta değerleri karşılaştırılırken iki farklı yaklaşım vardır:
NaNIEEE 754 şartnamesine uyan kendine eşit olmamalıdır .NaNEşdeğerlik ilişkisinin tanımlanması için gerekli olan refleksivitenin matematiksel özelliğini sağlayan kendisine eşit olmak
C # ( floatve 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 Equalsyö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,yvezboş olmayan nesne referanslarını temsil eder.x.Equals(x)truekayan 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,TupleveSystem.Numerics.Complex.BCL'de
Equalsrefleksif olmak yerine IEEE'yi takip eden herhangi bir örnek bilmiyorum . Sayaç örneklerSingle,Double,TupleveSystem.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,Exceptvs.) veri içeriyorsaNaNdeğ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
Equalsyöntem çoğu yüksek performans kodunu etkilemez.IEEE semantiğine veya performans avantajına ihtiyaç duyduğunuz durumlarda bir
IeeeEqualsyö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/ doubleve diğer bazı türler için ==ve Equalszaten 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 Equalsyine de diğer türlerle uğraşmak zorunda kalacaksınız. 2) Hemen hemen tüm jenerik algoritmalar / koleksiyonlar Equalsiş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 floatya da farklı bir "canavar" düşünün double. Bu önlemle, operatörün standartlarına uyma nedenini Equalsveya ==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 NaNsö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. ReflexiveEqualsSadece performans uğruna bir veya benzeri ile giderdim .
==veEqualsfarklı sonuçlar getirecekti. Birçok programcı olduklarını varsayalım ve bunu aynı şeyi . Ayrıca - genel olarak, eşitlik operatörlerinin uygulamalarıEqualsyöntemi çağırmaktadır . Birinin bir içerebileceğini iddia ettinizIeeeEquals, ancak biri bunu başka şekilde de yapabilir ve bir-ReflexiveEqualsyöntem içerebilir .Vector<float>-Tipi kullanılabilen çok performans açısından kritik uygulamalar ve buna göre optimize edilmelidir.