क्या यह 'लूप' के लिए रुकता है, और क्यों / क्यों नहीं? के लिए (var i = 0; 1 / i> 0; i ++) {}


104

क्या यह forपाश कभी रुकता है?

for (var i=0; 1/i > 0; i++) {
}

यदि हां, तो कब और क्यों? मुझे बताया गया कि यह रुक गया, लेकिन मुझे इसके लिए कोई कारण नहीं दिया गया।

Upddate

जांच के हिस्से के रूप में मैंने काफी लंबा और विस्तृत लेख लिखा है जो बताता है कि हुड के नीचे क्या चल रहा है - यहां आपको जावास्क्रिप्ट के नंबर प्रकार के बारे में जानने की आवश्यकता है


5
यह बंद नहीं होगा। कोड के इस Peice को क्रियान्वित करने का प्रयास करें। के लिए (var i = 0; 1 / i> 0; i ++) {कंसोल.लॉग (i)}
सौरभ अग्रवाल


3
Number.MAX_VALUE + 9.979202e291 == "इन्फिनिटी" और 1 / (NaN या 'इन्फिनिटी' या 'अपरिभाषित')> 0 == गलत।
Askeet

6
क्या जावास्क्रिप्ट उस लूप को अनदेखा करेगा क्योंकि उसके अंदर कोई बयान नहीं है? यानी इसे ऑप्टिमाइज़ करें? मुझे पता है कि कुछ संकलित भाषाएं होंगी।
ब्रायन जे

3
@askeet, जैसा कि गनबुल और अन्य नीचे बताते हैं, हम कभी भी बार-बार वृद्धि करके इन्फिनिटी तक नहीं पहुंचते हैं, इसके बजाय एक लूप में पकड़े जाते हैं Number.MAX_SAFE_INTEGER + 1
एलएसपीस

जवाबों:


128

(मैं मेटा-कंटेंट का प्रशंसक नहीं हूं, लेकिन: गनतुल और ले_म के उत्तर दोनों सही और उपयोगी हैं। वे मूल रूप से थे और इस समुदाय विकी के पोस्ट किए जाने के बाद किए गए संपादन के साथ और भी अधिक हैं । इस सीडब्ल्यू के लिए मूल प्रेरणा। मोटे तौर पर उन संपादनों के परिणामस्वरूप चला गया है, लेकिन यह उपयोगी बना हुआ है, इसलिए ... इसके अलावा: जबकि केवल कुछ लेखकों को सूचीबद्ध किया गया है, कई अन्य समुदाय के सदस्यों ने उन टिप्पणियों के साथ बहुत मदद की है जिन्हें अंदर और बाहर साफ किया गया है। सिर्फ नाम का सीडब्ल्यू नहीं है।)


सही ढंग से कार्यान्वित जावास्क्रिप्ट इंजन में लूप बंद नहीं होगा। (इंजन का मेजबान वातावरण अंततः इसे समाप्त कर सकता है क्योंकि यह अंतहीन है, लेकिन यह एक और बात है।)

यहाँ पर क्यों:

  1. शुरू में, जब iहै 0, हालत 1/i > 0सच है क्योंकि जावास्क्रिप्ट में, 1/0है Infinity, और Infinity > 0सच है।

  2. उसके बाद, iबढ़ाया जाएगा और लंबे समय तक एक सकारात्मक पूर्णांक मान के रूप में बढ़ता रहेगा (एक और 9,007,199,254,740,991 पुनरावृत्तियों)। उन सभी मामलों में, 1/iबने रहेंगे > 0(हालांकि अंत के 1/iलिए वास्तव में छोटे होने के लिए मूल्य !) और इसलिए लूप जारी रहता है और लूप को शामिल करता है जहां iमूल्य तक पहुंचता है Number.MAX_SAFE_INTEGER

  3. जावास्क्रिप्ट में नंबर IEEE-754 डबल-परिशुद्धता बाइनरी फ्लोटिंग पॉइंट हैं, एक काफी कॉम्पैक्ट प्रारूप (64 बिट्स) जो तेज गणना और एक विशाल श्रेणी प्रदान करता है। यह एक संकेत बिट, एक 11-बिट घातांक, और 52-बिट महत्व के रूप में संख्या को संग्रहीत करके करता है (हालांकि चतुराई के माध्यम से यह वास्तव में 53 बिट्स सटीक का हो जाता है)। यह बाइनरी (बेस 2) फ्लोटिंग पॉइंट है: महत्व (प्लस कुछ चतुरता) हमें मूल्य देता है, और घातांक हमें संख्या का परिमाण देता है।

    स्वाभाविक रूप से, इतने सारे महत्वपूर्ण बिट्स के साथ, हर संख्या को संग्रहीत नहीं किया जा सकता है। यहाँ संख्या 1 है, और 1 के बाद अगली उच्चतम संख्या है जो प्रारूप स्टोर कर सकती है, 1 + 2 -52 ≈ 1.00000000000000022, और उसके बाद अगला उच्चतम 1 + 2 × 2 -52 0000 1.00000000000000044:

       + ------------------------------------------------- -------------- साइन बिट
      / + ------- + ---------------------------------------- -------------- प्रतिपादक
     / / | + ------------------------------------------------- + - महत्व
    / / | / |
    0 01111111111 000000000000000000000000000000000000000000000000
                    = 1
    0 01111111111 000000000000000000000000000000000000000000000001
                    0000 1.00000000000000022
    0 01111111111 00000000000000000000000000000000000000000000000000
                    0000 1.00000000000000044
    

    1.00000000000000022 से 1.00000000000000044 पर कूदने पर ध्यान दें; 1.0000000000000003 स्टोर करने का कोई तरीका नहीं है। यह पूर्णांकों के साथ भी हो सकता है: Number.MAX_SAFE_INTEGER(9,007,199,254,740,991) उच्चतम धनात्मक पूर्णांक मान है कि प्रारूप जहां पकड़ सकता है iऔर i + 1दोनों बिल्कुल प्रतिनिधित्व योग्य हैं ( युक्ति )। 9,007,199,254,740,991 और 9,007,199,254,740,992 दोनों का प्रतिनिधित्व किया जा सकता है, लेकिन अगले पूर्णांक, 9,007,199,254,740,993 नहीं हो सकता; अगले पूर्णांक में हम 9,007,199,254,740,992 के बाद का प्रतिनिधित्व कर सकते हैं, जो 9,007,199,254,740,994 है। यहां थोड़ा सा पैटर्न दिया गया है, सबसे सही (सबसे महत्वपूर्ण) बिट पर ध्यान दें:

       + ------------------------------------------------- -------------- साइन बिट
      / + ------- + ---------------------------------------- -------------- प्रतिपादक
     / / | + ------------------------------------------------- + - महत्व
    / / | / |
    0 10000110011 1111111111111111111111111111111111111111111111111111111111
                    = 9007199254740991 (नंबर। MAX_SAFE_INTEGER)
    0 10000110100 000000000000000000000000000000000000000000000000
                    = 9007199254740992 (नंबर। MAX_SAFE_INTEGER + 1)
    x xxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                      9007199254740993 (Number.MAX_SAFE_INTEGER + 2) संग्रहीत नहीं किया जा सकता है
    0 10000110100 000000000000000000000000000000000000000000000001
                    = 9007199254740994 (नंबर। MAX_SAFE_INTEGER + 3)
    

    याद रखें, प्रारूप 2 आधार है, और उस घातांक के साथ कम से कम महत्वपूर्ण बिट अब आंशिक नहीं है; इसका मान 2 है। यह बंद हो सकता है (9,007,199,254,740,992) या (9,007,199,254,740,994); इसलिए इस बिंदु पर, हमने पूरे नंबर (पूर्णांक) के पैमाने पर भी सटीकता खोना शुरू कर दिया है। जिसका हमारे पाश के लिए निहितार्थ है!

  4. i = 9,007,199,254,740,992पाश पूरा करने के बाद , i++हमें देता है ... i = 9,007,199,254,740,992फिर से; इसमें कोई बदलाव नहीं है i, क्योंकि अगले पूर्णांक को संग्रहीत नहीं किया जा सकता है और गणना समाप्त हो जाती है। iअगर हम करते तो बदल जाते i += 2, लेकिन i++इसे बदल नहीं सकते। इसलिए हम स्थिर अवस्था में पहुँच गए हैं: iकभी नहीं बदलता है, और लूप कभी समाप्त नहीं होता है।

यहां विभिन्न प्रासंगिक गणनाएं दी गई हैं:

if (!Number.MAX_SAFE_INTEGER) {
  // Browser doesn't have the Number.MAX_SAFE_INTEGER
  // property; shim it. Should use Object.defineProperty
  // but hey, maybe it's so old it doesn't have that either
  Number.MAX_SAFE_INTEGER = 9007199254740991;
}
var i = 0;
console.log(i, 1/i, 1/i > 0); // 0, Infinity, true
i++;
console.log(i, 1/i, 1/i > 0); // 1, 1, true
// ...eventually i is incremented all the way to Number.MAX_SAFE_INTEGER
i = Number.MAX_SAFE_INTEGER;
console.log(i, 1/i, 1/i > 0); // 9007199254740991 1.1102230246251568e-16, true
i++;
console.log(i, 1/i, 1/i > 0); // 9007199254740992 1.1102230246251565e-16, true
i++;
console.log(i, 1/i, 1/i > 0); // 9007199254740992 1.1102230246251565e-16, true (no change)
console.log(i == i + 1);      // true


79

उत्तर:

हालत 1/i > 0हमेशा सच का मूल्यांकन करेगी:

  • प्रारंभ में यह सत्य है क्योंकि इसका 1/0मूल्यांकन Infinityऔर Infinity > 0सत्य है

  • यह सच है क्योंकि 1/i > 0सभी के लिए सच है i < Infinityऔर i++कभी नहीं पहुंचता है Infinity

i++कभी क्यों नहीं पहुंचता Infinity? Numberडेटाटाइप की सीमित परिशुद्धता के कारण , इसके लिए एक मूल्य है i + 1 == i:

9007199254740992 + 1 == 9007199254740992 // true

एक बार iउस मूल्य (जो मेल खाती है ) तक पहुंच जाता है , तो यह उसी के बाद भी रहेगा ।Number.MAX_SAFE_INTEGER + 1i++

इसलिए हमारे पास एक अनंत लूप है।


अनुबंध:

क्यों है 9007199254740992 + 1 == 9007199254740992?

जावास्क्रिप्ट का Numberडेटाटाइप वास्तव में 64-बिट IEEE 754 डबल सटीक फ्लोट है । प्रत्येक Numberको तीन भागों में विभाजित किया जाता है और संग्रहीत किया जाता है: 1-बिट संकेत, 11-बिट घातांक और 52-बिट मंटिसा। इसका मूल्य -1 साइन × मैन्टिसा × 2 एक्सपोनेंट है

9007199254740992 का प्रतिनिधित्व कैसे किया जाता है ? के रूप में 1.0 × 2 53 , या बाइनरी में:

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

मंटिसा के कम से कम महत्वपूर्ण बिट को बढ़ाते हुए, हमें अगली उच्च संख्या मिलती है:

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

उस नंबर का मूल्य 1.00000000000000022… × 2 53 = 9007199254740994 है

इसका क्या मतलब है? Numberया तो 900719925474099 2 या 900719925474099 4 हो सकता है , लेकिन बीच में कुछ भी नहीं।

अब, 900719925474099 2 + 1 का प्रतिनिधित्व करने के लिए हमने किसे चुना होगा ? आईईईई 754 गोलाई नियमों 900719925474099: जवाब देने के 2


9
छोटा और सही, वर्तमान स्वीकृत उत्तर से बेहतर
एलेक्सविन

@AlexWien स्वीकृत उत्तर एक समुदाय विकि स्वीकृत उत्तर है।
फुलवियो

2
मुझे पता नहीं है कि "समुदाय विकि उच्चारण" शब्द का उत्तर है। स्टैकओवरफ्लो के साथ इसका क्या करना है? यदि यह एक विदेशी लिंक है, तो एक लिंक प्रदान किया जाना चाहिए। स्टैकओवरफ़्लो पर स्वीकृत उत्तर हमेशा बदल सकते हैं, अर्जित स्थिति अंतिम नहीं है।
एलेक्सज्विन

"I ++ कभी इन्फिनिटी तक क्यों नहीं पहुंचता है? संख्या डेटाटाइप की सीमित परिशुद्धता के कारण ..." <- निश्चित रूप से यह अनंत तक नहीं पहुंचेगा, यहां तक ​​कि एक अनंत-सटीक संख्या प्रकार के साथ .. आप जानते हैं, क्योंकि आप गिन नहीं सकते हैं अनन्तता: पी
ब्लोर्बर्ड

1
@Blorgbeard आप सीमित परिशुद्धता वाले डबल्स से अनंत की गिनती कर सकते हैं , आपको बस 1 से अधिक बड़ी संख्या में वृद्धि करनी होगी, जैसे for (var i = 0; i < Infinity; i += 1E306);। लेकिन मुझे लगता है कि तुम कहाँ से आ रहे हो;)
le_m

27

Number.MAX_SAFE_INTEGERलगातार जावास्क्रिप्ट में अधिकतम सुरक्षित पूर्णांक प्रतिनिधित्व करता है। MAX_SAFE_INTEGERनिरंतर की एक मूल्य है 9007199254740991। उस संख्या के पीछे तर्क यह है कि जावास्क्रिप्ट आईईईई 754 में निर्दिष्ट के रूप में डबल-सटीक फ़्लोटिंग-पॉइंट फॉर्मेट नंबर का उपयोग करता है और केवल - (2 53 - 1) और 2 53 - 1 के बीच सुरक्षित रूप से संख्याओं का प्रतिनिधित्व कर सकता है ।

इस संदर्भ में सुरक्षित पूर्णांक का प्रतिनिधित्व करने और उनकी तुलना सही ढंग से करने की क्षमता को संदर्भित करता है। उदाहरण के लिए, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2मूल्यांकन करेगा true, जो गणितीय रूप से गलत है। Number.isSafeInteger()अधिक जानकारी के लिए देखें ।

क्योंकि MAX_SAFE_INTEGERकी एक स्थिर संपत्ति है Number, आप इसे हमेशा के रूप में उपयोग करते हैं Number.MAX_SAFE_INTEGER, बल्कि Numberआपके द्वारा बनाई गई वस्तु की संपत्ति के रूप में ।

अपडेट करें:

एक जवाब में किसी को हटा दिया गया था: iअनंत तक कभी नहीं पहुंचेगा। एक बार जब यह पहुंचता है Number.MAX_SAFE_INTEGER, i++तो चर को नहीं बढ़ाता है। यह वास्तव में सही नहीं है।

@TJ Crowder टिप्पणी है कि i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;है false। लेकिन अगला पुनरावृत्ति अपरिवर्तित स्थिति तक पहुंचता है, इसलिए मुख्य में उत्तर सही है।

iउदाहरण में कभी नहीं पहुँचता Infinity


2
विशेष रूप से, 9007199254740992 + 1है 9007199254740992
कोबी

1
@GerardoFurtado मुझे लगता है कि यह होगा।
फुलवियो

1
@GerardoFurtado for (var i=0; NaN > 0; i++) { console.log(i); }कुछ भी उत्पादन नहीं करेगा।
फुलवियो

2
@GerardoFurtado: उस स्थिति में, लूप बंद हो जाएगा। पाश शरीर सब पर कभी नहीं दर्ज किया जाना होता है, बहुत पहले टेस्ट (के बाद से 1/i > 0), झूठी होगा क्योंकि अगर iहै 0, 1/iहै NaN, और NaN > 0गलत है।
टीजे क्राउडर

1
@TJCrowder मैंने अपना उत्तर अपडेट कर दिया है। यह बात बताने के लिए धन्यवाद!
फुलवियो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.