(I == i + 1) {} लूप हमेशा के लिए मैं किस मूल्य के लिए करता हूं?


120

मैं ब्रिटेन के एक विश्वविद्यालय में एक उन्नत प्रोग्रामिंग पाठ्यक्रम से इस गूढ़ व्यक्ति को पार कर गया

निम्नलिखित लूप पर विचार करें, जिसमें मैं अब तक अघोषित है:

while (i == i + 1) {}

iइस लूप से पहले की परिभाषा खोजें , जैसे कि लूप हमेशा के लिए जारी रहता है।

अगला प्रश्न, जिसने इस कोड स्निपेट के लिए एक ही प्रश्न पूछा:

while (i != i) {}

मेरे लिए स्पष्ट था। बेशक इस अन्य स्थिति में यह है, NaNलेकिन मैं वास्तव में पहले से ही फंस गया हूं। क्या यह अतिप्रवाह के साथ करना है? जावा में हमेशा के लिए इस तरह के लूप का क्या कारण होगा?


3
.equals()विधि को ओवरराइड करने के लिए कोई संभावनाएं ? चूँकि मैं अघोषित है, हम किसी भी वर्ग का उपयोग कर सकते हैं।
जेनो चेन

7
@Raedwald "अनप्रोफेशनल" कोड का अध्ययन करते हुए आपको अधिक "पेशेवर" बनाता है, इसलिए ... वैसे भी, यह एक अच्छा सवाल है
एंड्रयू टोबिल्को

12
मजेदार तथ्य, C # में यह अशक्त संख्यात्मक प्रकारों के लिए भी काम करता है, जिनके मूल्य null, null == nullसत्य हैं और null + 1है null
एरिक लिपर्ट

4
@EricDuminil: स्थिति आपकी कल्पना से भी बदतर है। कई भाषाओं में, फ्लोटिंग पॉइंट अंकगणित को एक डबल द्वारा निर्दिष्ट कम से कम 64 बिट्स सटीकता से किया जाना चाहिए , जिसका अर्थ है कि यह कंपाइलर के चक्कर में उच्च परिशुद्धता में किया जा सकता है , और व्यवहार में ऐसा होता है । मैं आपको इस साइट पर C # प्रोग्रामर से एक दर्जन प्रश्नों के बारे में बता सकता हूं जो सोच रहे हैं कि 0.2 + 0.1 == 0.3संकलक सेटिंग्स, चंद्रमा के चरण और इसी तरह के आधार पर इसका मूल्य क्यों बदलता है।
एरिक लिपिपर्ट

5
@EricDuminil: इस गड़बड़ी का दोष इंटेल पर पड़ता है, जिसने हमें एक ऐसा चिप सेट दिया, जो उच्च-परिशुद्धता और तेज़ी से फ़्लोटिंग पॉइंट अंकगणित करता है यदि संख्याओं की गणना की जा सकती है, जिसका अर्थ है कि एक फ़्लोटिंग पॉइंट कंप्रेशन का परिणाम उनके मूल्यों को बदल सकता है ऑप्टिमाइज़र में रजिस्टर शेड्यूलर आज कितनी अच्छी तरह काम करता है। भाषा डिजाइनर के रूप में आपकी पसंद फिर से दोहराने योग्य संगणना और तेज़, सटीक संगणनाओं के बीच है , और फ़्लोटिंग पॉइंट गणित की परवाह करने वाला समुदाय बाद के लिए विकल्प चुन लेगा।
एरिक लिपर्ट

जवाबों:


142

सबसे पहले, चूंकि while (i == i + 1) {}लूप के मूल्य में बदलाव नहीं होता है , इसलिए iयह लूप को अनंत बना देता है, जो iकि संतोषजनक का मान चुनने के बराबर है i == i + 1

ऐसे कई मूल्य हैं:

चलो "विदेशी" के साथ शुरू करते हैं:

double i = Double.POSITIVE_INFINITY;

या

double i =  Double.NEGATIVE_INFINITY;

इन मूल्यों के संतोषजनक होने का कारण JLS 15.18.2i == i + 1 में बताया गया है
। संख्यात्मक प्रकार के लिए योजक संचालक (+ और -) :

एक अनंत और एक परिमित मूल्य का योग अनंत ऑपरेंड के बराबर है।

यह आश्चर्य की बात नहीं है, क्योंकि अनंत मूल्य के लिए एक परिमित मूल्य जोड़ने के परिणामस्वरूप एक अनंत मूल्य होना चाहिए।

उस ने कहा, iउस संतुष्टि के अधिकांश मूल्य i == i + 1बड़े double(या float) मूल्य हैं:

उदाहरण के लिए:

double i = Double.MAX_VALUE;

या

double i = 1000000000000000000.0;

या

float i = 1000000000000000000.0f;

doubleऔर floatप्रकार सीमित परिशुद्धता है, इसलिए यदि आप एक बड़ा पर्याप्त लेने doubleया floatमूल्य जोड़ने, 1यह करने के लिए एक ही मूल्य का परिणाम देगा।


10
या (double)(1L<<53)- याfloat i = (float)(1<<24)
dave_thompson_085

3
@ रूसन: कोई भी गणितज्ञ असहमत होगा। फ्लोटिंग पॉइंट नंबर बहुत कम समझ में आते हैं। वे गैर-सहयोगी, गैर-प्रतिवर्त (NaN! = NaN) हैं, और प्रतिस्थापित करने योग्य भी नहीं हैं (-0 == 0, लेकिन 1/0! = 1 / -0)। इसलिए बीजगणित की अधिकांश मशीनरी अनुचित है।
केविन

2
@ केविन जबकि फ्लोटिंग-पॉइंट नंबर वास्तव में सामान्य रूप से बहुत अधिक समझ में नहीं आता है, शिशुओं का व्यवहार (जो कि उस वाक्य में वर्णित है) को समझ बनाने के लिए डिज़ाइन किया गया था।
रुस्लान

4
@ केविन तैरने के लिए निष्पक्ष होना चाहिए, यदि आप अनन्तताओं या अपरिभाषित मूल्यों से निपटते हैं तो आप उन गुणों को ग्रहण नहीं कर सकते हैं जिन्हें आप बीजगणित में सूचीबद्ध करते हैं।
वू

2
@ केविन: IMHO, फ़्लोटिंग-पॉइंट मैथ्स बहुत अधिक समझ बना सकते थे यदि वे "सकारात्मक और नकारात्मक शून्य" की अवधारणाओं को प्रतिस्थापित करते थे, सकारात्मक, नकारात्मक और अहस्ताक्षरित "infinitesimals" के साथ-साथ "सच शून्य", और बनाया। खुद के बराबर एन.एन. ट्रू ज़ीरो सभी मामलों में एक एडिटिव पहचान के रूप में व्यवहार कर सकता है , और कुछ ऑपरेशन जिनमें इनफ़िनिटिमल्स द्वारा विभाजन शामिल होता है, उनके पूर्वाग्रह को खत्म कर देते हैं और यह मानते हैं कि इनफ़िनिटिमल्स सकारात्मक हैं।
सुपरकैट

64

इन पहेलियों को जोशुआ बलोच और नील गाफ्टर की पुस्तक "जावा पज़लर्स: ट्रैप्स, पॉटएप्स, एंड कॉर्नर केसेस" में विस्तार से वर्णित किया गया है।

double i = Double.POSITIVE_INFINITY;
while (i == i + 1) {}

या:

double i = 1.0e40;
while (i == i + 1) {}

दोनों, अनंत लूप में परिणाम होगा क्योंकि जोड़ने 1एक फ़्लोटिंग-बिंदु मान कि पर्याप्त रूप से बड़े मूल्य में परिवर्तन नहीं होगा है, क्योंकि यह अपने उत्तराधिकारी के लिए "की खाई को पाटने" नहीं है 1

दूसरी पहेली के बारे में एक नोट (भविष्य के पाठकों के लिए):

double i = Double.NaN;
while (i != i) {}

एक अनंत लूप में भी परिणाम होता है, क्योंकि NaN स्वयं 2 सहित किसी भी फ्लोटिंग-पॉइंट वैल्यू के बराबर नहीं है


1 - जावा गूढ़ व्यक्ति: जाल, नुकसान और कोने के मामले (अध्याय 4 - Loopy गूढ़ व्यक्ति)।

2 - जेएलएस .215.21.1



0

बस एक विचार: बुलियन के बारे में क्या?

bool i = TRUE;

क्या यह ऐसा मामला नहीं है i + 1 == i?


भाषा पर निर्भर करता है। जब एक इंट के साथ संयुक्त रूप से कई भाषाएं स्वचालित रूप से बूलियन को ले जाती हैं। जैसा कि आप सुझाव देते हैं अन्य लोग करते हैं - एक बूलियन के लिए इंटेक के साथ जबरदस्ती करना।
कार्ल विटथॉफ्ट

8
यह प्रश्न एक जावा प्रश्न है, और आपका सुझाव जावा में संकलन पास नहीं करता है (जिसके पास कोई +ऑपरेटर नहीं है जो एक booleanऔर एक intऑपरेंड के रूप में लेता है)।
एरन

@Eran: कि ऑपरेटर ओवरलोडिंग का पूरा विचार है। आप जावा बूलियन को C ++ वाले की तरह व्यवहार कर सकते हैं।
डोमिनिक

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