Double.NaN == Double.NaN गलत क्यों देता है?


155

मैं केवल OCPJP प्रश्नों का अध्ययन कर रहा था और मुझे यह अजीब कोड मिला:

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

जब मैंने कोड चलाया, मुझे मिला:

false
true

कैसे उत्पादन होता है falseजब हम दो चीजें हैं जो एक दूसरे के जैसा ही दिखाई देता तुलना कर रहे हैं? क्या NaNमतलब है?


8
यह वाकई अजीब है। क्योंकि Double.NaN स्थिर अंतिम है, == के साथ तुलना सही होनी चाहिए। प्रश्न के लिए +1।
Stephan

2
अजगर में भी यही बात है:In [1]: NaN==NaN Out[1]: False
tdc

58
सभी भाषाओं में यही बात सही है जो IEEE 754 मानक का सही ढंग से पालन करती है।
zzzzBov

4
अंतर्ज्ञान: "हैलो" एक संख्या नहीं है, सच (बूलियन) भी एक संख्या नहीं है। NaN! = NaN एक ही कारण के लिए "हैलो"! = True
केविन

3
@ स्टेपहान: Double.NaN==Double.NaNयदि Double.NaNप्रकार के थे, तो उनकी तुलना वास्तव में सही होनी चाहिए java.lang.Double। हालांकि, इसका प्रकार आदिम है double, और doubleलागू करने के लिए ऑपरेटर नियम (जो IEEE 754 के अनुरूप होने के लिए इस असमानता की मांग करता है, जैसा कि उत्तर में बताया गया है)।
सालेके

जवाबों:


139

NaN का अर्थ है "नॉट अ नम्बर"।

जावा भाषा विनिर्देश (JLS) तीसरा संस्करण कहता है :

एक ऑपरेशन जो ओवरफ्लो पर हस्ताक्षरित अनंत का उत्पादन करता है, एक ऐसा ऑपरेशन जो अंडरफ्लोज़ एक मूल्य मान या हस्ताक्षरित शून्य का उत्पादन करता है, और एक ऑपरेशन जिसमें कोई गणितीय निश्चित परिणाम नहीं होता है NaN पैदा करता है। एक संचालक के रूप में NaN के साथ सभी संख्यात्मक संचालन परिणामस्वरूप NaN का उत्पादन करते हैं। जैसा कि पहले ही वर्णित किया गया है, NaN तो एक अंकीय तुलना आपरेशन एक या दो Nans रिटर्न से जुड़े, अव्यवस्थित है falseऔर किसी भी !=NaN रिटर्न से जुड़े तुलना trueसहित, x!=xजब xNaN है।


4
@nibot: ज्यादातर सच है । IEEE- अनुरूप फ्लोट के साथ किसी भी तुलना का उत्पादन होगा false। तो यह मानक जावा से भिन्न है जिसमें IEEE मांगता है (NAN != NAN) == false
ड्रू डॉर्मन

2
इस पेंडोरा बॉक्स को खोलते हुए - जहाँ आप देखते हैं कि "IEEE मांग करता है कि (NAN! = NAN) == गलत"?
सुपरवाइजर

62

NaN की परिभाषा NaN सहित किसी भी संख्या के बराबर नहीं है। यह IEEE 754 मानक का हिस्सा है और CPU / FPU द्वारा कार्यान्वित किया जाता है। यह ऐसा कुछ नहीं है जिसमें जेवीएम को समर्थन देने के लिए कोई तर्क जोड़ना पड़े।

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

एक NaN के साथ एक तुलना हमेशा खुद के साथ तुलना करने पर भी एक अव्यवस्थित परिणाम देता है। ... समानता और असमानता की भविष्यवाणी गैर-सांकेतिक होती है, इसलिए x = x को गलत तरीके से लौटाने पर परीक्षण किया जा सकता है यदि x एक शांत NaN है।

जावा सभी NaN को शांत NaN मानता है।


1
क्या यह सीपीयू द्वारा कार्यान्वित किया गया है, या क्या यह जेवीएम में बोहेमियन उल्लेखों के रूप में हार्ड-वायर्ड है?
नविद चौगल १६'१२

3
जेवीएम को कॉल करना होगा जो भी इसे सही तरीके से लागू करेगा। एक पीसी पर, सीपीयू सभी काम ऐसे करता है। इस समर्थन के बिना एक मशीन पर JVM को इसे लागू करना होगा। (मैं ऐसी किसी भी मशीन के बारे में नहीं जानता)
पीटर लॉरी

उस दिन वापस जब 8087 एक विकल्प था, सी लाइब्रेरी में एक एफपी एमुलेटर था। जेवीएम जैसे कार्यक्रमों को इसके बारे में किसी भी तरह से चिंता करने की आवश्यकता नहीं होगी।
लोर्ने

49

वह तर्क क्यों

NaNका मतलब है Not a Number। एक संख्या क्या नहीं है? कुछ भी। आपके पास एक तरफ कुछ भी हो सकता है और दूसरी तरफ कुछ भी हो सकता है, इसलिए कुछ भी गारंटी नहीं देता है कि दोनों समान हैं। NaNके साथ गणना की है Double.longBitsToDouble(0x7ff8000000000000L)और जैसा कि आप देख सकते हैं longBitsToDouble:

यदि तर्क सीमा में कोई मूल्य है 0x7ff0000000000001L के माध्यम से 0x7fffffffffffffffLया श्रेणी में 0xfff0000000000001Lके माध्यम से 0xffffffffffffffffL, परिणाम एक है NaN

साथ ही, NaNएपीआई के अंदर तार्किक रूप से व्यवहार किया जाता है।


प्रलेखन

/** 
 * 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;

वैसे, NaN है आपके कोड नमूने के रूप परीक्षण किया गया है:

/**
 * 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);
}

उपाय

आप जो कर सकते हैं उसका उपयोग करें compare / compareTo:

Double.NaNइस विधि द्वारा अपने आप को समान माना जाता है और अन्य सभी doubleमूल्यों से अधिक (सहित) Double.POSITIVE_INFINITY ) से बड़ा है।

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

या equals:

यदि thisऔर argumentदोनों प्रतिनिधित्व करते हैं Double.NaN, तो equalsविधि वापस आ जाती है true, भले ही Double.NaN==Double.NaNमूल्य हो false

Double.NaN.equals(Double.NaN);

क्या आप किसी ऐसे मामले के बारे में जानते हैं, जहां NaN != NaNझूठे होने से कार्यक्रम NaN != NaNसच होने की तुलना में अधिक जटिल हो जाएंगे? मुझे पता है कि IEEE ने निर्णय उम्र से पहले किया था, लेकिन व्यावहारिक दृष्टिकोण से, मैंने कभी ऐसे मामले नहीं देखे हैं जहां यह उपयोगी है। यदि किसी ऑपरेशन को तब तक चलाना चाहिए, जब तक कि पुनरावृत्तियों में समान परिणाम न मिलें, तब तक लगातार दो पुनरावृत्तियों के होने से NaN को "स्वाभाविक रूप से" का पता चलेगा, क्योंकि बाहर निकलने की स्थिति यह व्यवहार के लिए नहीं थी।
सुपरकाट

@supercat आप कैसे कह सकते हैं कि दो यादृच्छिक गैर संख्या स्वाभाविक रूप से बराबर हैं? या कहें, आदिम समान? उदाहरण के रूप में NaN के बारे में सोचें, न कि कुछ आदिम। प्रत्येक अलग-अलग असामान्य परिणाम कुछ अजीब का एक अलग उदाहरण है और भले ही दोनों को एक ही प्रतिनिधित्व करना चाहिए, == के लिए अलग-अलग उदाहरणों को गलत लौटना चाहिए। दूसरी ओर, बराबरी का उपयोग करते समय इसे ठीक से संभाला जा सकता है जैसा कि आप इरादा करते हैं। [ docs.oracle.com/javase/7/docs/api/java/lang/…
falsarella

@falsarella: मुद्दा यह नहीं है कि क्या दो यादृच्छिक संख्याओं को "निश्चित रूप से बराबर" माना जाना चाहिए, बल्कि यह है कि किन मामलों में किसी भी संख्या की तुलना "निश्चित रूप से असमान" होना ही उपयोगी है। यदि कोई इसकी सीमा की गणना करने की कोशिश कर रहा है f(f(f...f(x))), और कोई व्यक्ति y=f[n](x)कुछ nऐसा खोजता है, जिसके परिणामस्वरूप से f(y)अविभाज्य है y, तो yकिसी और अधिक गहराई से नेस्टेड के परिणाम से अप्रभेद्य होगा f(f(f(...f(y)))। यहां तक ​​कि अगर कोई NaN==NaNझूठा होना चाहता था , तो Nan!=Nan भी झूठ होना x!=xकुछ एक्स के लिए सच होने से कम "आश्चर्यजनक" होगा ।
सुपरकैट

1
@falsarella: मेरा मानना ​​है कि प्रकार Double.NaNनहीं है Double, लेकिन double, इसलिए प्रश्न एक के व्यवहार से संबंधित है double। हालांकि ऐसे कार्य मौजूद हैं जो एक समतुल्य संबंध doubleमूल्यों के लिए परीक्षण कर सकते हैं, एकमात्र सम्मोहक उत्तर जो मुझे "क्यों" (जो मूल प्रश्न का हिस्सा है) के लिए पता है "क्योंकि IEEE में कुछ लोगों को समानता-परीक्षण नहीं करना चाहिए एक तुल्यता संबंध को परिभाषित करें "। बीटीडब्ल्यू, क्या केवल आदिम-संचालकों का उपयोग करके परीक्षण करने xऔर yतुल्यता के लिए कोई संक्षिप्त मुहावरेदार तरीका है ? मुझे पता है कि सभी योगों को स्पष्ट नहीं किया गया है।
18

1
सबसे अच्छा और सरल जवाब। धन्यवाद
तरुण नागपाल

16

यह सवाल का सीधा जवाब नहीं हो सकता है। लेकिन अगर आप जांचना चाहते हैं कि क्या आपके लिए कुछ समान है Double.NaNतो आपको इसका उपयोग करना चाहिए:

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

यह वापस आ जाएगी true


6

Double.NaN के लिए जावाडोक यह सब कहते हैं:

प्रकार का नॉट-ए-नंबर (NaN) मान रखने वाला निरंतर double। यह द्वारा लौटाए गए मूल्य के बराबर है Double.longBitsToDouble(0x7ff8000000000000L)

दिलचस्प है, इस प्रकार Doubleपरिभाषित करने के लिए स्रोत NaN:

public static final double NaN = 0.0d / 0.0;

आपके द्वारा वर्णित विशेष व्यवहार JVM में हार्ड-वायर्ड है।


5
क्या यह जेवीएम में हार्ड वायर्ड है, या इसे सीपीयू द्वारा पीटर उल्लेख के रूप में लागू किया गया है?
नवेद चौगल

4

प्रति के रूप में, डबल सटीक संख्या के लिए अस्थायी अंक अंकगणित के लिए IEEE मानक ,

IEEE डबल सटीक फ़्लोटिंग पॉइंट मानक प्रतिनिधित्व के लिए 64 बिट शब्द की आवश्यकता होती है, जिसे 0 से 63 तक दर्शाया जा सकता है, दाएं से बाएं

यहां छवि विवरण दर्ज करें कहाँ पे,

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

यदि E=2047(सभी Eहैं 1) और Fनॉनजेरो है, तो V=NaN("नॉट ए नंबर")

जिसका मतलब है,

यदि सभी Eबिट 1 हैं, और यदि कोई गैर-शून्य बिट है Fतो संख्या हैNaN

इसलिए, दूसरों के बीच, निम्नलिखित सभी संख्याएँ हैं NaN:

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

विशेष रूप से, आप परीक्षण नहीं कर सकते

if (x == Double.NaN) 

यह जांचने के लिए कि क्या कोई विशेष परिणाम बराबर है Double.NaN, क्योंकि सभी "एक संख्या नहीं" मानों को अलग माना जाता है। हालाँकि, आप Double.isNaNविधि का उपयोग कर सकते हैं :

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

3

NaN एक विशेष मूल्य है जो "एक संख्या नहीं" को दर्शाता है; यह कुछ अवैध अंकगणितीय परिचालनों का परिणाम है, जैसे कि sqrt(-1), और इसमें (कभी-कभी कष्टप्रद) संपत्ति होती है NaN != NaN


2

नहीं एक संख्या संचालन के परिणाम का प्रतिनिधित्व करती है जिसका परिणाम एक संख्या के साथ प्रतिनिधित्व करने योग्य नहीं है। सबसे प्रसिद्ध ऑपरेशन 0/0 है, जिसका परिणाम ज्ञात नहीं है।

इस कारण से, NaN किसी भी चीज़ के बराबर नहीं है (अन्य गैर-संख्या मान सहित)। अधिक जानकारी के लिए, विकिपीडिया पृष्ठ देखें: http://en.wikipedia.org/wiki/NaN


-1: यह के परिणाम का प्रतिनिधित्व नहीं करता है 0/00/0जैसे - NaN हमेशा होता है, लेकिन NaN अन्य कार्यों का परिणाम हो सकता है 2+NaN: an operation that has no mathematically definite result produces NaN, के रूप में @AdrianMitev द्वारा प्रति जवाब
ANeves

वास्तव में, NaN का अर्थ "नॉट ए नंबर" है, और यह उन सभी परिचालनों का परिणाम है जिनके परिणामस्वरूप अपरिभाषित या अप्राप्य मूल्य है। सबसे प्रसिद्ध और आम ऑपरेशन 0/0 है, लेकिन जाहिर है कि कई अन्य ऑपरेशन भी हैं, जिनके परिणाम समान हैं। मैं मानता हूं कि मेरे उत्तर में सुधार किया जा सकता है, लेकिन मैं -1 से असहमत हूं ... मैंने अभी-अभी जांच की कि विकिपीडिया भी एक NaN परिणाम के साथ ऑपरेशन के पहले उदाहरण के रूप में 0/0 संचालन का उपयोग करता है ( en.wikipedia.org/wiki/ ना ))।
मत्तेयो

इसके अलावा, यह डबल के लिए जावा स्रोत में है: सार्वजनिक स्थिर अंतिम डबल NaN = 0.0d / 0.0;
गिलाउम

1
@ मत्तो +0, अब जब कि गलत बयान गया है। और मेरे -1 या +1 आपके लिए सहमत या असहमत नहीं हैं; लेकिन -1 के साथ एक टिप्पणी छोड़ना अच्छा है, ताकि लेखक समझ सके कि उसका उत्तर अप्रयुक्त क्यों माना जाता है - और यदि वह चाहे तो इसे बदल सकता है।
एनेव्स

@Guillaume अगर वह टिप्पणी मेरे लिए थी, तो कृपया इसे पुनःप्रकाशित करें: मैं इसे नहीं समझता।
एनेव्स

0

इस लिंक के अनुसार , इसमें विभिन्न परिस्थितियां हैं और याद रखना मुश्किल है। यह वह है जो मुझे याद है और उन्हें अलग करता है। NaNउदाहरण के लिए "गणितीय रूप से अपरिभाषित" का अर्थ है: "0 से विभाजित 0 का परिणाम अपरिभाषित है" और क्योंकि यह अपरिभाषित है, इसलिए "अपरिभाषित से संबंधित तुलना निश्चित रूप से अपरिभाषित है"। इसके अलावा, यह गणितीय परिसर की तरह अधिक काम करता है। दूसरी ओर, सकारात्मक और नकारात्मक दोनों अनंत और पूर्वनिर्धारित हैं, उदाहरण के लिए "सकारात्मक या नकारात्मक अनंत बड़े को अच्छी तरह से गणितीय रूप से परिभाषित किया गया है"।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.