Double.NaN == Double.NaN neden yanlış döndürüyor?


155

Sadece OCPJP sorularını inceliyordum ve şu garip kodu buldum:

public static void main(String a[]) {
    System.out.println(Double.NaN==Double.NaN);
    System.out.println(Double.NaN!=Double.NaN);
}

Kodu çalıştırdığımda, var:

false
true

falseBirbirine aynı görünen iki şeyi karşılaştırdığımızda çıktı nasıl ? Ne anlama NaNgeliyor?


8
Bu gerçekten garip. Double.NaN statik son olduğundan, == ile karşılaştırma doğru dönmelidir. Soru için +1.
Stephan

2
Aynı şey python için de geçerlidir:In [1]: NaN==NaN Out[1]: False
tdc

58
Aynı şey IEEE 754 standardını doğru şekilde takip eden tüm dillerde geçerlidir.
zzzzBov

4
Sezgi: "Merhaba" bir sayı değil, true (boole) da bir sayı değildir. NaN! = NaN aynı nedenden dolayı "Merhaba"! = True
Kevin

3
@Stephan: ile karşılaştırılması Double.NaN==Double.NaNdurumunda gerçekten doğru dönmelidir Double.NaNtipi vardı java.lang.Double. Bununla birlikte, tipi ilkeldir doubleve operatör için doubleuygulama kuralları (cevaplarda açıklandığı gibi IEEE 754 ile uyumluluk için bu eşitsizliği talep eder).
sleske

Yanıtlar:


139

NaN "Sayı Değil" anlamına gelir.

Java Dil Belirtimi (JLS) Üçüncü Sürüm :

Taşan bir işlem, işaretli bir sonsuzluk, düşük değerdeki bir işlem denormalize değer veya işaretli bir sıfır üretir ve matematiksel olarak kesin bir sonucu olmayan bir işlem NaN üretir. Bir işlenen olarak NaN ile yapılan tüm sayısal işlemler sonuç olarak NaN üretir. Daha önce açıklandığı gibi, NaN sıralanmamıştır, bu nedenle bir veya iki NaN geri dönüşünü içeren bir sayısal karşılaştırma işlemi falseve !=NaN ne zaman truedahil olmak üzere NaN geri dönüşlerini içeren herhangi bir karşılaştırma .x!=xx


4
@nibot: Çoğunlukla doğrudur . IEEE uyumlu bir şamandıra ile herhangi bir karşılaştırma üretilecektir false. Bu standart, IEEE'nin talep etmesi bakımından Java'dan farklıdır (NAN != NAN) == false.
Drew Dormann

2
Bu Pandora'nın kutusunu açmak - "IEEE'nin (NAN! = NAN) == yanlış" olmasını istediğini görüyorsunuz?
Danışman

62

NaN tanım gereği NaN dahil herhangi bir sayıya eşit değildir. Bu IEEE 754 standardının bir parçasıdır ve CPU / FPU tarafından uygulanır. JVM'nin desteklemek için herhangi bir mantık eklemesi gereken bir şey değil.

http://en.wikipedia.org/wiki/NaN

Bir NaN ile karşılaştırma, kendisi ile karşılaştırılsa bile her zaman sırasız bir sonuç döndürür. ... Eşitlik ve eşitsizlik tahminleri sinyal vermediği için x = x return false, x'in sessiz bir NaN olup olmadığını test etmek için kullanılabilir.

Java tüm NaN'ye sessiz NaN gibi davranır.


1
CPU tarafından mı uygulanıyor, yoksa JVM'de Bohemian'dan bahsedildiği gibi kablo bağlantılı mı?
Naweed Chougle

3
JVM, onu doğru şekilde uygulayacak olan her şeyi çağırmalıdır. Bilgisayarda CPU tüm işleri bu şekilde yapar. Bu desteği olmayan bir makinede JVM bunu uygulamak zorundadır. (Böyle bir makine bilmiyorum)
Peter Lawrey

8087'nin bir seçenek olduğu günlerde, C kütüphanesinde bir FP emülatörü vardı. JVM gibi programlar bunun için endişelenmek zorunda kalmazdı.
Lorne Marquis

49

Neden bu mantık

NaNanlamına gelir Not a Number. Sayı nedir? Herhangi bir şey. Bir tarafta ve diğer tarafta herhangi bir şey olabilir, bu yüzden hiçbir şey her ikisinin de eşit olduğunu garanti etmez. dokümantasyonunda görebileceğiniz ve aşağıdaki gibi NaNhesaplanır :Double.longBitsToDouble(0x7ff8000000000000L)longBitsToDouble

Bağımsız değişken aralığında bir değerde ise 0x7ff0000000000001Lyoluyla 0x7fffffffffffffffLya da aralığı 0xfff0000000000001Lthrough 0xffffffffffffffffLsonucu meydana gelir NaN.

Ayrıca, NaNAPI içinde mantıksal olarak ele alınır.


belgeleme

/** 
 * A constant holding a Not-a-Number (NaN) value of type
 * {@code double}. It is equivalent to the value returned by
 * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
 */
public static final double NaN = 0.0d / 0.0;

Bu arada, NaN bir kod örneği olarak test:

/**
 * Returns {@code true} if the specified number is a
 * Not-a-Number (NaN) value, {@code false} otherwise.
 *
 * @param   v   the value to be tested.
 * @return  {@code true} if the value of the argument is NaN;
 *          {@code false} otherwise.
 */
static public boolean isNaN(double v) {
    return (v != v);
}

Çözüm

Ne yapabilirsiniz olan kullanım compare/ compareTo:

Double.NaNbu yöntemle kendisine eşit ve diğer tüm doubledeğerlerden (dahil Double.POSITIVE_INFINITY) daha büyük olduğu düşünülür .

Double.compare(Double.NaN, Double.NaN);
Double.NaN.compareTo(Double.NaN);

Veya equals:

Eğer thisve argumentikisi de temsil Double.NaN, daha sonra equalsbu metot bize true, olsa bile Double.NaN==Double.NaNdeğeri vardır false.

Double.NaN.equals(Double.NaN);

NaN != NaNSahte olmanın , programları NaN != NaNgerçek olmaktan daha karmaşık hale getireceği bir durum biliyor musunuz ? IEEE'nin kararları yıllar önce verdiğini biliyorum, ancak pratik bir bakış açısıyla, yararlı olduğu vakaları hiç görmedim. Bir işlemin ardışık yinelemeler aynı sonucu verene kadar çalışması gerekiyorsa, iki ardışık yinelemenin NaN verimi olması, bu davranış için olmasaydı bir çıkış koşulu olarak "doğal olarak" algılanacaktır.
supercat

@supercat İki rasgele olmayan sayının doğal olarak eşit olduğunu nasıl söyleyebilirsiniz? Yoksa ilkel olarak eşit mi? NaN'yi ilkel bir şey değil, bir örnek olarak düşünün. Her farklı anormal sonuç, garip bir şeyin farklı bir örneğidir ve her ikisi de aynı şeyi temsil etse bile, farklı örnekler için == kullanılması false döndürmelidir. Öte yandan, eşittir kullanırken, istediğiniz gibi düzgün bir şekilde ele alınabilir. [ docs.oracle.com/javase/7/docs/api/java/lang/…
falsarella

@falsarella: Mesele, iki rasgele sayının "kesinlikle eşit" olarak kabul edilip edilmeyeceği değil, hangi durumlarda herhangi bir sayının "kesinlikle eşit olmayan" olarak karşılaştırılması yararlıdır. Biri sınırını hesaplamak için çalışıyorsa f(f(f...f(x)))ve bir buluntu bir y=f[n](x)bazıları için nsonucu böyle f(y)ayırt edilemez y, sonra ybir daha-Çok fazla iç içe durumundan ayırt edilemeyecek olacaktır f(f(f(...f(y))). Bile biri istedik NaN==NaNsahip yanlış olduğu Nan!=Nan da olmasından daha az "şaşırtıcı" olacağını false olması x!=xbazı x için doğru.
supercat

1
@falsarella: Bence türün Double.NaNböyle olmadığına inanıyorum Double, ama doublesoru şu davranışı ile ilgili bir soru double. doubleDeğerleri içeren bir denklik ilişkisini test edebilen işlevler olmasına rağmen , "neden" (orijinal sorunun bir parçası olan) için bildiğim tek zorlayıcı cevap "çünkü IEEE'deki bazı insanlar eşitlik testinin yapılması gerektiğini düşünmedi "denklik ilişkisini tanımlar". BTW, test etmek xve ysadece ilkel operatörleri kullanarak denklik için özlü deyimsel bir yol var mı? Bildiğim tüm formülasyonlar oldukça tıknaz.
supercat

1
en iyi ve basit cevap. Teşekkür ederim
Tarun Nagpal

16

Bu soruya doğrudan bir cevap olmayabilir. Ancak bir şeyin eşit olup olmadığını kontrol etmek Double.NaNistiyorsanız bunu kullanmalısınız:

double d = Double.NaN
Double.isNaN(d);

Bu geri dönecek true


6

Double.nan için javadoc her şeyi anlatıyor:

Sayı Değil (NaN) türünde bir sabit double. Tarafından döndürülen değere eşittir Double.longBitsToDouble(0x7ff8000000000000L).

İlginç bir şekilde, kaynak Doubletanımlayıp NaN, böylece:

public static final double NaN = 0.0d / 0.0;

Açıkladığınız özel davranış JVM'ye bağlanmıştır.


5
JVM'de kablo bağlantılı mı yoksa Peter tarafından bahsedildiği gibi CPU tarafından mı uygulanıyor?
Naweed Chougle

4

uyarınca, Çift Hassasiyetli sayılar için kayan noktalı aritmetik için IEEE standardını ,

IEEE çift kesinlikli kayar nokta standart gösterimi, soldan sağa 0'dan 63'e kadar numaralandırılmış olarak temsil edilebilecek 64 bitlik bir kelime gerektirir

resim açıklamasını buraya girin nerede,

S: Sign  1 bit
E: Exponent  11 bits
F: Fraction  52 bits 

Eğer E=2047(hepsi Evardır 1) ve Fdaha sonra sıfırdan farklı olduğu V=NaN( "Bir sayı değil")

Yani,

Tüm Ebitler 1 ise ve içinde sıfır olmayan bir bit Fvarsa sayı olur NaN.

bu nedenle, diğerleri arasında, aşağıdaki tüm sayılar NaN,

0 11111111 0000000000000000010000000000000000000000000000000000 = NaN
1 11111111 0000010000000000010001000000000000001000000000000000 = NaN
1 11111111 0000010000011000010001000000000000001000000000000000 = NaN

Özellikle, test edemezsiniz

if (x == Double.NaN) 

belirli bir sonucun eşit olup olmadığını kontrol etmek Double.NaN, çünkü tüm “sayı değil” değerleri ayrı kabul edilir. Ancak, Double.isNaNyöntemi kullanabilirsiniz :

if (Double.isNaN(x)) // check whether x is "not a number"

3

NaN "sayı değil" anlamına gelen özel bir değerdir; bu gibi bazı geçersiz aritmetik işlemlerin sonucudur sqrt(-1)ve (bazen sinir bozucu) özelliğe sahiptir NaN != NaN.


2

Sayı değil, sonucu bir sayı ile temsil edilemeyen işlemlerin sonucunu temsil etmez. En ünlü operasyon sonucu bilinmeyen 0/0.

Bu nedenle, NaN hiçbir şeye eşit değildir (diğer bir sayı olmayan değerler dahil). Daha fazla bilgi için wikipedia sayfasını kontrol edin: http://en.wikipedia.org/wiki/NaN


-1: O mu değil sonucunu temsil 0/0. 0/0her zaman NaN'dir, ancak NaN diğer işlemlerin sonucu olabilir - örneğin 2+NaN: an operation that has no mathematically definite result produces NaN@AdrianMitev'in cevabına göre
ANeves

Gerçekten de, NaN "Sayı Değil" anlamına gelir ve sonuç olarak tanımlanmamış veya tekrarlanamayan bir değere sahip olan tüm işlemlerin sonucudur. En ünlü ve ortak operasyon 0/0, ancak açıkçası aynı sonuca sahip tonlarca başka operasyon var. Cevabımın geliştirilebileceğine katılıyorum, ancak -1'e katılmıyorum ... Ayrıca wikipedia'nun bir NaN sonucu ile ilk operasyon örneği olarak 0/0 işlemlerini kullandığını kontrol ettim ( en.wikipedia.org/wiki/ NaN ).
Matteo

Ayrıca bu, Double için Java kaynağındadır: public static final double NaN = 0.0d / 0.0;
Guillaume

1
@Matteo +0, şimdi yanlış ifade gitti. Ve -1 veya +1'm kabul ya da katılmaman için değil; ancak -1 ile bir yorum bırakmak iyidir, böylece yazar cevabının neden gereksiz olarak kabul edildiğini anlayabilir - ve eğer isterse değiştirebilir.
ANeves

@Guillaume bu yorum benim için yazılmışsa, lütfen tekrar ifade edin: Anlamıyorum.
ANeves

0

Bu bağlantıya göre , çeşitli durumları var ve hatırlanması zor. Onları bu şekilde hatırlıyorum ve ayırt ediyorum. NaN"matematiksel olarak tanımlanmamış" anlamına gelir: örneğin: "0'a bölünen 0 sonucunun tanımsız olduğu" ve tanımsız olduğu için "tanımsız ile ilgili karşılaştırma elbette tanımsızdır". Ayrıca, daha çok matematiksel tesisler gibi çalışır. Öte yandan, hem pozitif hem de negatif sonsuz önceden tanımlanmıştır ve tanımlayıcıdır, örneğin "pozitif ya da negatif sonsuz büyük matematikte iyi tanımlanmıştır".

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.