जब तक System.out.println का उपयोग नहीं किया जाता है, तब तक अंतहीन लूप समाप्त हो जाता है


91

मेरे पास एक सरल सा कोड था जो कि एक अंतहीन लूप माना जाता था क्योंकि xहमेशा बढ़ता रहेगा और हमेशा इससे बड़ा रहेगा j

int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
   x = x + y;
}
System.out.println(y);

लेकिन जैसा है, यह प्रिंट yकरता है और अंतहीन रूप से लूप नहीं करता है। मैं यह क्यों नहीं समझ सकता। हालाँकि, जब मैं निम्नलिखित तरीके से कोड समायोजित करता हूं:

int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
    x = x + y;
    System.out.println(y);
}
System.out.println(y);

यह एक अंतहीन लूप बन जाता है और मुझे पता नहीं क्यों। क्या जावा अपने अंतहीन लूप को पहचानता है और इसे पहली स्थिति में छोड़ देता है, लेकिन दूसरी विधि में कॉल करना पड़ता है, इसलिए यह अपेक्षित व्यवहार करता है? उलझन में :)


4
दूसरा लूप अंतहीन है क्योंकि ऊपरी सीमा लूप चर की तुलना में तेजी से xबढ़ती है । दूसरे शब्दों में, ऊपरी सीमा से कभी नहीं टकराएगा, इसलिए लूप "हमेशा के लिए" चलेगा। ठीक है, हमेशा के लिए नहीं, आपको सबसे अधिक संभावना किसी बिंदु पर एक अतिप्रवाह मिलेगा। jj
टिम बेगेलेसेन

75
यह एक अंतहीन लूप नहीं है, यह सिर्फ इतना है कि पहले मामले में लूप से बाहर आने के लिए लूप से 238609294 बार लगता है और दूसरी बार यह y238609294 बार के मूल्य को प्रिंट करता है
N00b Pr0grammer

13
एक शब्द का जवाब: अतिप्रवाह
qwr

20
अंत में , System.out.println(x)इसके बजाय yअंत में तुरंत दिखाया जाएगा कि समस्या क्या थी
जॉली जोकर

9
@TeroLahtinen नहीं, यह नहीं होगा। जावा भाषा युक्ति पढ़ें यदि आपको संदेह है कि अंतर प्रकार क्या है। यह हार्डवेयर स्वतंत्र है।
9ilsdx 9rvj 0lo

जवाबों:


161

दोनों उदाहरण अंतहीन नहीं हैं।

मुद्दे की सीमा है int जावा में प्रकार (या किसी अन्य सामान्य भाषा में बहुत अधिक)। जब मूल्य xपहुंचता है 0x7fffffff, तो किसी भी सकारात्मक मूल्य को जोड़ने से अतिप्रवाह होगा और xनकारात्मक हो जाएगा, इसलिए की तुलना में कम हैj

पहले और दूसरे लूप के बीच अंतर यह है कि आंतरिक कोड में अधिक समय लगता है और xओवरफ्लो होने तक शायद कई मिनट लगते हैं । पहले उदाहरण के लिए इसे दूसरे से भी कम समय लग सकता है या सबसे शायद कोड को ऑप्टिमाइज़र द्वारा हटा दिया जाएगा क्योंकि इसका कोई प्रभाव नहीं है।

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


48
मैंने सिर्फ एक प्रोग्राम (अपने लैपटॉप पर) की कोशिश की, जो लूप में एक लाइन प्रिंट करता है। मैंने इसे समयबद्ध किया, और यह लगभग 1000 लाइनें / सेकंड प्रिंट करने में सक्षम था। N00b की टिप्पणी के आधार पर कि लूप 238609294 बार निष्पादित होगा, लूप को समाप्त करने में लगभग 23861 सेकंड का समय लगेगा - 6.6 घंटे से अधिक। "कई मिनट" से अधिक एक बालक।
अंज

11
@ अजब: कार्यान्वयन पर निर्भर करता है। println()विंडोज पर IIRC एक ब्लॉकिंग ऑपरेशन है, जबकि (कुछ?) यूनिक्स इसका बफर है इसलिए बहुत तेजी से आगे बढ़ता है। यह भी प्रयोग करने की कोशिश करें print()कि कौन सा बफ़र जब तक यह हिट नहीं करता \n(या बफर भरता है, या flush()कहा जाता है)
BlueRaja - Danny Pflughoeft

6
साथ ही यह आउटपुट दिखाने वाले टर्मिनल पर निर्भर करता है। एक अत्यधिक उदाहरण के लिए stackoverflow.com/a/21947627/53897 देखें (जहां शब्द रैपिंग के कारण धीमा था)
Thorbjørn Ravn Andersen

1
हाँ, यह UNIX पर बफ़र्ड है, लेकिन यह अभी भी अवरुद्ध है। एक बार जब 8K या तो बफर भर जाता है, यह तब तक अवरुद्ध रहेगा जब तक कि वहाँ कमरा न हो। यह कितनी जल्दी खपत होती है, इस पर निर्भर करता है। / Dev / null में आउटपुट को रीडायरेक्ट करना सबसे तेज़ होगा, लेकिन इसे टर्मिनल पर भेजे जाने के बाद, डिफ़ॉल्ट रूप से, स्क्रीन पर ग्राफिक्स अपडेट की आवश्यकता होगी और बहुत अधिक गणना शक्ति के रूप में यह फोंट को धीमा करता है।
पेंगुइन

2
@Zbynek ओह, शायद ऐसा है, लेकिन जो मुझे याद दिलाता है, टर्मिनलों I / O को आमतौर पर लाइन बफ़र किया जा रहा है, ब्लॉक नहीं है, इसलिए सबसे अधिक संभावना है कि हर प्रिंटलाइन में सिस्टम कॉल के परिणामस्वरूप टर्मिनल केस धीमा हो जाएगा।
पेंगुइन ४३

33

चूंकि उन्हें इंट घोषित किया जाता है, एक बार जब यह अधिकतम मूल्य तक पहुंच जाता है, तो लूप टूट जाएगा क्योंकि एक्स मूल्य नकारात्मक हो जाएगा।

लेकिन जब System.out.println को लूप में जोड़ा जाता है, तो निष्पादन की गति दिखाई देती है (क्योंकि कंसोल पर आउटपुट निष्पादन की गति को धीमा कर देगा)। हालांकि, यदि आप दूसरे प्रोग्राम को (लूप के अंदर सिसो को) लंबे समय तक चलने देते हैं, तो इसका व्यवहार पहले वाले (लूप के अंदर सिसो के बिना) के समान होना चाहिए।


21
लोगों को एहसास नहीं है कि सांत्वना के लिए कितना स्पैमिंग उनके कोड को धीमा कर सकता है।
user9993

13

इसके दो कारण हो सकते हैं:

  1. जावा forलूप का अनुकूलन करता है और चूंकि लूप के बाद का कोई उपयोग नहीं है x, बस लूप को हटा देता है। आप System.out.println(x);लूप के बाद स्टेटमेंट डालकर इसे चेक कर सकते हैं ।

  2. यह संभव हो सकता है कि जावा वास्तव में लूप का अनुकूलन नहीं कर रहा है और यह कार्यक्रम को सही ढंग से निष्पादित कर रहा है और अंततः अतिप्रवाह और अतिप्रवाह के xलिए बढ़ेगा int। पूर्णांक अतिप्रवाह संभवतः पूर्णांक xको ऋणात्मक बना देगा जो कि j से छोटा होगा और इसलिए यह लूप से बाहर आएगा और के मान को प्रिंट करेगा y। यह System.out.println(x);लूप के बाद जोड़कर भी चेक किया जा सकता है ।

इसके अलावा, पहले मामले में भी अंततः अतिप्रवाह होगा इस प्रकार इसे दूसरे मामले में प्रस्तुत करना होगा ताकि यह कभी भी एक वास्तविक अंतहीन लूप न हो।


14
मैं दरवाजा नंबर 2 का चयन करता हूं
रॉबी कॉर्नेलिसन

सच। यह नकारात्मक पैमाने पर चला गया और लूप से बाहर निकल गया। लेकिन एक sysoutअनंत लूप का भ्रम जोड़ने के लिए बहुत धीमा है।
पवन कुमार

4
1. एक बग होगा। कंपाइलर अनुकूलन को किसी प्रोग्राम के व्यवहार को बदलने की अनुमति नहीं है। यदि यह एक अनंत लूप था, तो कंपाइलर इसे सभी इच्छित का अनुकूलन कर सकता है, हालांकि, परिणाम अभी भी एक अनंत लूप होना चाहिए। वास्तविक समाधान यह है कि ओपी गलत है: दोनों में से कोई भी अनंत लूप नहीं है, एक दूसरे की तुलना में अधिक काम करता है, इसलिए इसमें अधिक समय लगता है।
जोर्ग डब्ल्यू मित्तग

1
@ JörgWMittag इस मामले में x एक स्थानीय चर है जिसका किसी और चीज से कोई संबंध नहीं है। जैसे कि यह संभव है कि इसे दूर से अनुकूलित किया जाए। लेकिन किसी को यह देखने के लिए कि क्या मामला है, यह निर्धारित करने के लिए बायटेकोड को देखना चाहिए कि कंपाइलर ने ऐसा कुछ नहीं किया।
उम्मीद है कि

1

वे दोनों अंतहीन लूप नहीं हैं, शुरू में j = 0, जब तक j <x, j बढ़ता है (j ++), और j एक पूर्णांक है इसलिए लूप तब तक चलेगा जब तक कि यह अधिकतम मूल्य तक नहीं पहुंच जाता है तब ओवरफ्लो (एक पूर्णांक अतिप्रवाह) की स्थिति है ऐसा तब होता है जब एक अंकगणितीय ऑपरेशन का परिणाम, जैसे गुणा या जोड़, इसे स्टोर करने के लिए उपयोग किए जाने वाले पूर्णांक प्रकार के अधिकतम आकार से अधिक होता है।) दूसरे उदाहरण के लिए सिस्टम सिर्फ y के मूल्य को तब तक प्रिंट करता है जब तक कि लूप टूट न जाए।

यदि आप एक अंतहीन लूप का उदाहरण देख रहे हैं, तो इसे इस तरह दिखना चाहिए

int x = 6;

for (int i = 0; x < 10; i++) {
System.out.println("Still Looping");
}

क्योंकि (x) कभी भी 10 का मान प्राप्त नहीं करेगा;

आप लूप के लिए एक डबल के साथ एक अनंत लूप भी बना सकते हैं:

int i ;

  for (i = 0; i <= 10; i++) {
      for (i = 0; i <= 5; i++){
         System.out.println("Repeat");   
      }
 }

यह लूप अनंत है क्योंकि लूप के लिए पहला i <10 है, जो कि सच है इसलिए यह लूप के लिए दूसरे में जाता है और लूप के लिए दूसरा तब (i) का मान बढ़ाता है जब तक कि यह == 5. तब यह पहले में आगे बढ़ता है लूप के लिए फिर से क्योंकि मैं <10, प्रक्रिया खुद को दोहराती रहती है क्योंकि यह लूप के लिए दूसरे के बाद रीसेट करता है


1

यह एक महीन लूप है क्योंकि एक बार से xअधिक का मूल्य 2,147,483,647(जो कि अधिकतम मूल्य है int), xनकारात्मक हो जाएगा और jकिसी भी अधिक से अधिक नहीं होगा , चाहे आप y प्रिंट करें या नहीं।

तुम बस के मूल्य बदल सकते हैं yकरने के लिए 100000और प्रिंट yपाश में और पाश बहुत जल्द ही टूट जाएगा।

आप जिस कारण से इसे अनंत मानते हैं, वह यह है कि System.out.println(y);कोड को बिना किसी क्रिया के बहुत धीमी गति से निष्पादित किया जाता है।


0

दिलचस्प समस्या वास्तव में दोनों मामलों में लूप अंतहीन नहीं है

लेकिन उनके बीच मुख्य अंतर यह है कि यह कब समाप्त होगा और xअधिकतम intमूल्य को पार करने में कितना समय लगेगा जो इसके 2,147,483,647बाद अतिप्रवाह की स्थिति में पहुंच जाएगा और लूप समाप्त हो जाएगा।

इस समस्या को समझने का सबसे अच्छा तरीका एक सरल उदाहरण का परीक्षण करना और उसके परिणामों को संरक्षित करना है।

उदाहरण :

for(int i = 10; i > 0; i++) {}
System.out.println("finished!");

आउटपुट:

finished!
BUILD SUCCESSFUL (total time: 0 seconds)

इस अनंत लूप का परीक्षण करने के बाद इसे समाप्त होने में 1 सेकंड से भी कम समय लगेगा।

for(int i = 10; i > 0; i++) {
    System.out.println("infinite: " + i);
}
System.out.println("finished!");

आउटपुट:

infinite: 314572809
infinite: 314572810
infinite: 314572811
.
.
.
infinite: 2147483644
infinite: 2147483645
infinite: 2147483646
infinite: 2147483647
finished!
BUILD SUCCESSFUL (total time: 486 minutes 25 seconds)

इस परीक्षण मामले पर आप कार्यक्रम को समाप्त करने और समाप्त करने में लगने वाले समय में भारी अंतर देखेंगे।

यदि आप धैर्य नहीं रखते हैं, तो आप सोचेंगे कि यह लूप अंतहीन है और समाप्त नहीं होगा, लेकिन वास्तव में इसे समाप्त होने में घंटों का समय लगेगा और iमूल्य पर अतिप्रवाह स्थिति तक पहुंच जाएगा ।

अंत में हम लूप के लिए प्रिंट स्टेटमेंट डालने के बाद निष्कर्ष निकालते हैं कि प्रिंट स्टेटमेंट के बिना पहले मामले में लूप की तुलना में अधिक समय लगेगा।

कार्यक्रम को चलाने के लिए लिया गया समय आपके कंप्यूटर की विशिष्टताओं पर निर्भर करता है विशेष प्रसंस्करण शक्ति (प्रोसेसर क्षमता), ऑपरेटिंग सिस्टम और आपका आईडीई जो प्रोग्राम को संकलित कर रहा है।

मैं इस मामले का परीक्षण करता हूं:

Lenovo 2.7 GHz Intel Core i5

ओएस: विंडोज 8.1 64x

आईडीई: नेटबीन्स 8.2

कार्यक्रम को समाप्त करने में लगभग 8 घंटे (486 मिनट) लगते हैं।

इसके अलावा, आप देख सकते हैं कि लूप के लिए कदम वृद्धि i = i + 1 अधिकतम अंतर मान तक पहुंचने के लिए बहुत धीमी कारक है।

हम इस कारक को बदल सकते हैं और कम समय में लूप का परीक्षण करने के लिए कदम बढ़ा सकते हैं।

अगर हम इसे डालते हैं i = i * 10और इसका परीक्षण करते हैं:

for(int i = 10; i > 0; i*=10) {
           System.out.println("infinite: " + i);
}
     System.out.println("finished!");

आउटपुट:

infinite: 100000
infinite: 1000000
infinite: 10000000
infinite: 100000000
infinite: 1000000000
infinite: 1410065408
infinite: 1215752192
finished!
BUILD SUCCESSFUL (total time: 0 seconds)

जैसा कि आप देखते हैं कि यह पिछले लूप की तुलना में बहुत तेज़ है

कार्यक्रम को समाप्त करने और समाप्त करने में 1 सेकंड से भी कम समय लगता है।

इस परीक्षण के उदाहरण के बाद मुझे लगता है कि इसे समस्या को स्पष्ट करना चाहिए और Zbynek Vyskovsky की वैधता साबित होती है - kvr000 का जवाब , यह भी इस सवाल का जवाब होगा ।

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