IEEE754 NaN değerleri için yanlış dönen tüm karşılaştırmalar için gerekçe nedir?


267

NaN değerlerinin karşılaştırılması neden diğer değerlerden farklı davranıyor? Yani, ==, <=,> =, <,> operatörleriyle yapılan tüm karşılaştırmalar, bir veya her iki değer NaN'dir, diğer tüm değerlerin davranışının aksine yanlış döndürür.

Bunun sayısal hesaplamaları bir şekilde basitleştirdiğini düşünüyorum, ancak Kahan'ın IEEE 754'ün Durumu ile ilgili diğer tasarım kararlarını ayrıntılı olarak tartışan Ders Notlarında bile açıkça belirtilen bir neden bulamadım .

Bu sapkın davranış, basit veri işleme yaparken sorun yaratır. Örneğin, bir C programında bazı gerçek değerli alan wrt kayıt listesi sıralarken Ben maksimum öğe olarak NaN işlemek için ekstra kod yazmanız gerekir, aksi takdirde sıralama algoritması karışık olabilir.

Düzenleme: Şimdiye kadar cevapların hepsi NaNs karşılaştırmak anlamsız olduğunu savunuyor.

Kabul ediyorum, ancak bu doğru cevabın yanlış olduğu anlamına gelmez, bunun yerine Neyse ki var olmayan bir Boolean Değil (NaB) olacaktır.

Bu yüzden karşılaştırmalar için doğru veya yanlış döndürme seçimi benim görüşümde ve genel veri işleme için, olağan yasalara (== yansıma, <, ==,> trikotomi), en yeni veri yapılarına uyması avantajlı olacaktır. bu yasalara dayanan karışık olur.

Bu yüzden, sadece felsefi akıl yürütme değil, bu yasaları çiğnemenin somut bir avantajını istiyorum.

Edit 2: Sanırım neden NaN'i maksimal yapmanın kötü bir fikir olacağını anladım, üst limitlerin hesaplanmasını bozacaktı.

NaN! = NaN, örneğin bir döngüde yakınsamanın saptanmasını önlemek için arzu edilebilir.

while (x != oldX) {
    oldX = x;
    x = better_approximation(x);
}

ancak mutlak farkı küçük bir limitle karşılaştırarak daha iyi yazılmalıdır. IMHO bu NaN'de refleksiviteyi kırmak için nispeten zayıf bir argüman.


2
Bir NaN hesaplamaya girdiğinde, tipik olarak asla ayrılmaz, bu nedenle yakınsama testiniz sonsuz bir döngü haline gelir. Muhtemelen NaN döndürerek çağrı rutinine yakınsama başarısızlığını bildirmek genellikle tercih edilir. Böylece, döngü yapısı tipik olarak while (fabs(x - oldX) > threshold)yakınsama meydana gelirse veya bir NaN hesaplamaya girerse döngüden çıkarak benzer bir şey olur. NaN'nin tespiti ve uygun çözüm, döngü dışında gerçekleşir.
Stephen Canon

1
NaN ise while döngüsünün hala işe yarayacağı düzenin asgari elemanı olsaydı.
starblue

Yanıtlar:


535

IEEE-754 komitesinin üyesiydim, işleri biraz açıklığa kavuşturmaya yardımcı olacağım.

İlk olarak, kayan nokta sayıları gerçek sayılar değildir ve kayan nokta aritmetiği gerçek aritmetiğin aksiyomlarını karşılamaz. Trikotomi, gerçek aritmetiğin yüzer için geçerli olmayan tek özelliği değil, hatta en önemlisi değildir. Örneğin:

  • Toplama çağrışımsal değildir.
  • Dağıtım kanunu geçerli değildir.
  • Tersine çevrilmemiş kayan nokta sayıları vardır.

Devam edebilirdim. Bildiğimiz ve sevdiğimiz gerçek aritmetiğin tüm özelliklerini karşılayan sabit boyutlu bir aritmetik türü belirtmek mümkün değildir . 754 komitesi bazılarını bükmeye veya kırmaya karar vermek zorundadır. Bu, bazı oldukça basit ilkeler tarafından yönlendirilmektedir:

  1. Mümkün olduğunda, gerçek aritmetik davranışını eşleştiriyoruz.
  2. Yapamadığımızda, ihlalleri mümkün olduğunca öngörülebilir ve teşhis edilmesi kolay hale getirmeye çalışıyoruz.

"Bu doğru cevabın yanlış olduğu anlamına gelmez" yorumuna gelince, bu yanlıştır. Yüklem daha küçük (y < x)olup olmadığını sorar . Eğer NaN ise, o zaman olduğu değil herhangi kayan nokta değerinden düşük cevap mutlaka yanlıştır yüzden.yxyx

Trikotominin kayan nokta değerleri için geçerli olmadığını belirttim. Ancak, benzer bir özellik var. 754-2008 standardının 5.11, 2. paragrafı:

Dört birbirini dışlayan ilişki mümkündür: küçük, eşit, büyük ve düzensiz. Son durum, en az bir işlenen NaN olduğunda ortaya çıkar. Her NaN sıralamasız olarak kendisi de dahil olmak üzere her şeyi karşılaştırır.

NaN'leri işlemek için ekstra kod yazarken, kodunuzu NaN'lerin düzgün bir şekilde düşeceği şekilde yapılandırmak genellikle (her zaman kolay olmasa da) mümkündür, ancak bu her zaman böyle değildir. Değilse, bazı ekstra kodlar gerekli olabilir, ancak bu, cebirsel kapanışın kayan nokta aritmetiğine getirdiği rahatlığı ödemek için küçük bir fiyattır.


Zeyilname: Birçok yorumcu, NaN! = NaN'ı benimsemenin, bilinen herhangi bir aksiyomu korumadığı görülmediği gerekçesiyle, eşitlik ve trikotominin refleksivitesini korumanın daha yararlı olacağını savunmuştur. Bu bakış açısına sempati duyduğumu itiraf ediyorum, bu yüzden bu cevabı tekrar gözden geçirip biraz daha fazla bağlam sunacağımı düşündüm.

Kahan'la konuşmamdaki anlayışım NaN! = NaN'nin iki pragmatik düşünceden kaynaklandığı yönündedir:

  • Bu mümkün olduğunda x == yeşdeğer olmalıdır x - y == 0(gerçek aritmetik teoremi olmanın ötesinde, bu, donanımın uygulanmasını daha fazla yer verimli hale getirir, bu da standardın geliştirildiği zaman çok önemlidir - ancak bunun x için ihlal edildiğine dikkat edin. = y = sonsuzluk, bu yüzden tek başına büyük bir neden değil; makul bir şekilde bükülmüş olabilir (x - y == 0) or (x and y are both NaN)).

  • Daha da önemlisi, isnan( )NaN'nin 8087 aritmetiğinde resmileştirildiği sırada hiçbir belirti yoktu ; programcılara, programlama dillerine bağlı olmayan ve isnan( )uzun yıllar alabilecek bir şey sağlayan NaN değerlerini tespit etmek için uygun ve etkili bir yol sağlamak gerekiyordu. Kahan'ın konuyla ilgili kendi yazılarını alıntılayacağım:

NaN'lerden kurtulmanın bir yolu olmasaydı, bunlar CRAY'lardaki belirsizlikler kadar işe yaramazdı; karşılaşır karşılaşmaz, belirsiz bir sonuca belirsiz bir süre devam etmek yerine hesaplama en iyi şekilde durdurulacaktır. Bu yüzden NaN'ler üzerindeki bazı operasyonlar NaN dışı sonuçlar vermelidir. Hangi operasyonlar? … İstisnalar, C, "x == x" ve "x! = X" tahminlerini içerir; bunlar, her sonsuz veya sonlu x sayısı için sırasıyla 1 ve 0'dır, ancak x, bir Sayı Değil (NaN) ise tersidir; bunlar, NaN'ler ve NaN için bir kelime içermeyen dillerdeki bir sayılar ve isNaN (x) arasındaki tek basit istisnai ayrımı sağlar.

Bunun aynı zamanda “A-Boolean Değil” gibi bir şeyi döndürmeyi engelleyen mantık olduğunu da unutmayın. Belki de bu pragmatizm yanlış yerleştirilmişti ve standardın zorunlu olması gerekirdi isnan( ), ancak bu, dünya dilinin benimsenmesini programlamayı beklerken, NaN'yi birkaç yıl boyunca verimli ve rahat bir şekilde kullanmak neredeyse imkansız olurdu. Bunun makul bir ödünleşme olacağına ikna olmadım.

Açık konuşmak gerekirse: NaN == NaN sonucu artık değişmeyecek. Onunla yaşamayı öğrenmek internette şikayet etmekten daha iyidir. Kaplar için uygun bir sipariş ilişkisinin de olması gerektiğini iddia etmek isterseniz , favori programlama dilinizin totalOrderIEEE-754 (2008) 'de standartlaştırılmış yüklemi uygulamasını tavsiye etmenizi öneririm . Şu anda Kahan'ın mevcut durumu motive eden endişesinin geçerliliğinden bahsetmemiş olması.


16
Nokta 1 ve 2'yi okudum. Sonra gerçek aritmetik olarak (ilk etapta NaN'ye izin vermek için uzatılmış) NaN'nin kendisine eşit olduğunu gözlemledim - çünkü matematikte, herhangi bir varlık istisnasız kendisine eşittir. Şimdi kafam karıştı: Neden IEEE "gerçek aritmetik davranışıyla eşleşmedi", ki bu NaN == NaN yapar? Neyi kaçırıyorum?
en fazla

12
Kabul; NaN'lerin geri dönüşümsüzlüğü, eşitlik temelli içerme semantiği ile Python gibi diller için acı yaratmadı. Sen gerçekten sen bunun üstüne inşa kaplara çalışırken bir denklik ilişkisi olduğu başarısız eşitlik istemiyoruz. Ve iki ayrı eşitlik kavramına sahip olmak, öğrenmesi kolay olması gereken bir dil için de kolay bir seçenek değildir. Sonuç (Python söz konusu olduğunda), IEEE 754'e saygı ile çok kırılmamış çevreleme semantiği arasında hoş olmayan derecede kırılgan bir uzlaşmadır. Neyse ki, NaN'leri kaplara koymak nadirdir.
Mark Dickinson

5
Burada bazı güzel gözlemler: bertrandmeyer.com/2010/02/06/…
Mark Dickinson

6
@StephenCanon: Hangi şekilde (0/0) == (+ INF) + (-INF) sahip olmaktan daha saçma olurdu 1f/3f == 10000001f/30000002f? Kayan nokta değerleri eşdeğerlik sınıfları olarak kabul edilirse, o a=bzaman "Getirilen hesaplamalar ave bsonsuz hassasiyetle yapılırsa özdeş sonuçlar verir" anlamına gelmez , daha çok "Hakkında bilinenlerle aeşleşmeler hakkında bilinenler b". Eğer "Nan! = NaN" olması başka türlü olacak daha basit şeyler yapar kod herhangi bir örnek biliyorsanız merak ediyorum?
supercat

5
Teorik olarak, NaN == NaN'niz varsa ve isNaN'ınız yoksa, yine de NaN'yi test edebilirsiniz !(x < 0 || x == 0 || x > 0), ancak daha yavaş ve daha hantal olurdu x != x.
user2357112 Monica

50

NaN tanımlanmamış bir durum / sayı olarak düşünülebilir. 0/0 kavramının undefined veya sqrt (-3) kavramına benzer (kayan noktanın yaşadığı gerçek sayı sisteminde).

NaN, bu tanımlanmamış durum için bir tür yer tutucu olarak kullanılır. Matematiksel olarak, undefined, undefined ile eşit değildir. Tanımlanmamış bir değerin başka bir tanımlanmamış değerden daha büyük veya daha küçük olduğunu da söyleyemezsiniz. Bu nedenle, tüm karşılaştırmalar yanlış döndürür.

Bu davranış, sqrt (-3) ile sqrt (-2) arasında karşılaştığınız durumlarda da avantajlıdır. Her ikisi de NaN döndürürler, ancak aynı değeri döndürmelerine rağmen eşdeğer değildirler. Bu nedenle, NaN ile uğraşırken eşitlik her zaman yanlış dönen arzu edilen davranıştır.


5
Sqrt (1.00000000000000022) == sqrt (1.0) sonucu ne olmalıdır? (1E308 + 1E308-1E308-1E308-1E308) == (1E308 + 1E308) hakkında ne dersiniz? Ayrıca, altı karşılaştırmanın sadece beşi yanlış döndürür. !=Operatör true döndürür. Her ikisi de işlenenler NaN olduğunda ya da seçeneğini seçerek, x ve y'yi karşılaştıran kodun yanlış döndürülmesine NaN==NaNve NaN!=NaNher ikisinin de NaN olduğunda ne olacağını seçmesine izin verir . ==!=
supercat

38

Başka bir benzetme yapmak için. Size iki kutu teslim edersem ve hiçbirinin elma içermediğini söylesem, kutuların aynı şeyi içerdiğini söyler misiniz?

NaN, bir şeyin ne olduğu hakkında değil, sadece ne olduğu hakkında hiçbir bilgi içermez. Dolayısıyla bu unsurların kesinlikle eşit olduğu söylenemez.


6
Tüm boş kümeler tanım gereği eşittir.
MSalters

28
Size verilen kutuların boş olduğu bilinmemektedir.
John Smith

7
Kutuların aynı şeyi içermediğini söyler misiniz? Bunun mantığını anlayabiliyorum (NaN==Nan)==false. Anlamadığım şey bunun mantığı (Nan!=Nan)==true.
supercat

3
NaN! = NaN'nin doğru olduğunu varsayıyorum çünkü x! = Y! (X == y) olarak tanımlanmıştır. Kabul edersek, IEEE spesifikasyonunun onu bu şekilde tanımlayıp tanımlamadığını bilmiyorum.
Kef Schecter

6
Ama bu benzetmede, bana bir kutu verdiyseniz, elma içermediğini söyledi, sonra bana kendisinin eşit olup olmadığını sordu, hayır dememi mi bekliyorsunuz? Çünkü IEEE'ye göre söylemem gerekecekti.
noktalı virgül

12

NaN hakkındaki wikipedia makalesinde , aşağıdaki uygulamalar NaN'lere neden olabilir:

  • Tüm matematiksel işlemler> en az bir işlenen olarak NaN ile
  • 0/0, ∞ / ∞, ∞ / -∞, -∞ / ∞ ve -∞ / -∞ bölümleri
  • 0 × ∞ ve 0 × -∞ çarpımları
  • ∞ + (-∞), (-∞) + ∞ ilaveleri ve eşdeğer çıkarma.
  • Negatif bir sayının kare kökünü almak, negatif bir sayının logaritmasını almak, 90 dereceden (veya π / 2 radyan) tek bir katının teğetini almak veya ters sinüsü almak da dahil olmak üzere, alanın dışındaki argümanlara bir işlev uygulamak veya -1'den küçük veya +1'den büyük bir sayının kosinüsü.

Bu operasyonlardan hangisinin NaN'yi yarattığını bilmenin bir yolu olmadığından, bunları karşılaştırmanın mantıklı bir yolu yoktur.


3
Dahası, hangi operasyonu bilseniz bile, yardımcı olmaz. Bir noktada 0 / 0'a giden, (sürekliliği varsayarsak) o noktada iyi tanımlanmış ve farklı değerlere sahip çok sayıda formül oluşturabilirim.
David Thornley

4

Tasarım gerekliliğini bilmiyorum, ama burada IEEE 754-1985 standardından bir alıntı:

"İşlenen biçimleri farklı olsa bile kayan nokta sayılarını desteklenen tüm biçimlerde karşılaştırmak mümkün olacaktır. Karşılaştırmalar tamdır ve asla taşmaz veya taşmaz. Karşılıklı olarak dört dört ilişki mümkündür: daha küçük, eşit, daha büyük ve sırasız Son durum, en az bir işlenen NaN olduğunda ortaya çıkar. Her NaN, kendisi de dahil olmak üzere her şeyi sırasız olarak karşılaştırır. "


2

Sadece tuhaf görünüyor çünkü NaN'lere izin veren çoğu programlama ortamı da 3 değerli mantığa izin vermiyor. Karışıma 3 değerli mantık atarsanız, tutarlı olur:

  • (2.7 == 2.7) = doğru
  • (2.7 == 2.6) = yanlış
  • (2.7 == NaN) = bilinmiyor
  • (NaN == NaN) = bilinmiyor

.NET bile bir bool? operator==(double v1, double v2)işleç sağlamaz , bu yüzden aptalca (NaN == NaN) = falsesonuçla sıkışıp kalırsınız .


1

NaN (Bir Sayı Değil) tam olarak şu anlama gelir: Bu bir sayı değil ve bu yüzden karşılaştırmak gerçekten mantıklı değil.

nullİşlenenlerle SQL'de aritmetik gibi biraz : Hepsi sonuçlanır null.

Kayan nokta sayıları için yapılan karşılaştırmalar sayısal değerleri karşılaştırır. Bu nedenle, sayısal olmayan değerler için kullanılamazlar. NaN bu nedenle sayısal anlamda karşılaştırılamaz.


3
Diyerek şöyle devam etti: "Bu bir sayı değil ve bu yüzden karşılaştırmak gerçekten mantıklı değil." Dizeler sayı değildir, ancak karşılaştırmak mantıklıdır.
jason

2
evet, bir dizeyi bir dizeyle karşılaştırmak mantıklıdır. Ancak bir ipin, örneğin elma ile karşılaştırılması pek mantıklı değil. Elma ve armut sayı olmadığından, bunları karşılaştırmak mantıklı mıdır? Hangisi daha büyük?
Daren Thomas

@DarenThomas: SQL'de hiçbiri "IF NULL = NULL THEN FOO;" ne de "Null <> Null THEN CALL FOO;" [veya sözdizimi ne olursa olsun] yürütülür FOO. NaN'nin eşdeğer if (NaN != NaN) foo();olması için çalıştırılmaması gerekir foo, ama yapar.
supercat

1

Aşırı basitleştirilmiş cevap, bir NaN'nin sayısal bir değere sahip olmamasıdır, bu nedenle içinde başka bir şeyle karşılaştırılacak hiçbir şey yoktur.

+ INF gibi davranmalarını istiyorsanız, NaN'lerinizi test etmeyi ve yerine + INF eklemeyi düşünebilirsiniz.


0

NaN'ın herhangi bir gerçek sayı ile karşılaştırılmasının uyumsuz olması gerektiğine katılırken, NaN'nin kendisiyle karşılaştırılmasının sadece bir nedeni olduğunu düşünüyorum. Örneğin, NaN sinyalleri ile sessiz NaN sinyalleri arasındaki fark nasıl keşfedilir? Sinyalleri bir Boole değerleri kümesi (yani bir bit-vektör) olarak düşünürsek, bit-vektörlerinin aynı mı yoksa farklı mı olduğunu sorabilir ve kümeleri buna göre sıralayabilir. Örneğin, maksimum önyargılı bir üs kodunun çözülmesinde, anlamlılık, anlamlılığın en önemli bitini ikili formatın en önemli bitine hizalanacak şekilde kaydırılırsa, negatif bir değer sessiz bir NaN olur ve herhangi bir pozitif değer sinyal NaN olmak. Sıfır elbette sonsuzluğa ayrılmıştır ve karşılaştırma düzensiz olacaktır. MSB hizalaması, farklı ikili formatlardan bile sinyallerin doğrudan karşılaştırılmasına izin verecektir. Aynı sinyal kümesine sahip iki NaN eşdeğerdir ve eşitliğe anlam verir.


-1

Benim için bunu açıklamanın en kolay yolu:

Bir şeyim var ve elma değilse o zaman portakal mı?

NaN'yi başka bir şeyle (kendisinin bile) karşılaştıramazsınız çünkü değeri yoktur. Ayrıca herhangi bir değer olabilir (bir sayı hariç).

Bir şey var ve bir sayıya eşit değilse o zaman bir dize mi?


Ne demek "sayı dışında herhangi bir değer olabilir"?
Puşkin

-2

Çünkü matematik, sayıların "sadece var olduğu" alandır. Bilgisayar size gerekir başlatmak bu sayıları ve tutmak sizin ihtiyaçlarına göre devlet. O eski günlerde bellek başlatma asla güvenemeyeceğiniz şekillerde çalıştı. "Ah, 0xCD ile her zaman başlatılacak, algo'm kırılmayacak" diye düşünmenize asla izin veremezdiniz .

Bu nedenle , algoritmanızın emilmesine ve kırılmasına izin vermeyecek kadar yapışkan olan uygun karıştırmayan çözücüye ihtiyacınız vardır . Sayıları içeren iyi algoritmalar çoğunlukla ilişkilerle çalışacak ve () ilişkileri atlanacak olanlar.

Bu, bilgisayar belleğinden rastgele cehennemi programlamak yerine, yeni değişkene yaratabileceğiniz yağdır. Ve algoritmanız her ne ise, kırılmaz.

Daha sonra, aniden algoritmanızın NaN ürettiğini öğrendiğinizde, her şubeye birer birer bakarak temizlemek mümkündür. Yine, "her zaman yanlış" kural bu konuda çok yardımcı oluyor.


-4

Çok kısa cevap:

Çünkü aşağıdakiler: nan / nan = 1 TUTMAMALIDIR. Aksi takdirde inf/inf1 olur.

(Bu nedenle naneşit olamaz nan. Arşimet mülkünü tatmin eden bir sette herhangi bir emir ilişkisine saygı duyulursa >veya kabul <edilirse nan, yine nan / nan = 1sınırda oluruz ).


2
Hayır, bu mantıklı değil. Biz inf = infve inf / inf = nanbu yüzden, nan = nanengel olmaz nan / nan = nanya.
starblue

@starblue Bunu nan / nan = 1mu demek istediniz ? Her neyse ... Eğer inf ve nan diğer sayılar gibi olsaydı, mantığınız mantıklı. Durum böyle değil. Nedeni inf/infolmalı nan(veya belirsiz matematik formu) ve 1basit cebirsel manipülasyon (De L'Hospital teoremi bakınız) daha ince olduğunu.
SeF
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.