Int i = 1024 * 1024 * 1024 * 1024 त्रुटि के बिना संकलन क्यों करता है?


152

की सीमा int-2147483648 से 2147483647 है।

अगर मैं इनपुट

int i = 2147483648;

फिर ग्रहण "2147483648" के तहत एक लाल रेखा को संकेत देगा।

लेकिन अगर मैं ऐसा करता हूं:

int i = 1024 * 1024 * 1024 * 1024;

यह ठीक संकलन करेगा।

public class Test {
    public static void main(String[] args) {        

        int i = 2147483648;                   // error
        int j = 1024 * 1024 * 1024 * 1024;    // no error

    }
}

शायद यह जावा में एक मूल प्रश्न है, लेकिन मुझे नहीं पता कि दूसरा संस्करण कोई त्रुटि क्यों पैदा करता है।


10
यहां तक ​​कि अगर कंपाइलर सामान्य रूप से अनुकूलन के रूप में एक ही मूल्य में गणना को "ढह" देगा, तो ऐसा नहीं होगा यदि परिणाम एक अतिप्रवाह होगा, क्योंकि कोई भी अनुकूलन कार्यक्रम के व्यवहार को नहीं बदलना चाहिए।
हॉट लक्स

1
और यह व्याख्या नहीं कर सकता2147483648 : यह शाब्दिक अर्थ नहीं है।
डेसिट सेगुरेट जूल

1
और जावा पूर्णांक ओवरफ्लो की रिपोर्ट नहीं करता है - ऑपरेशन "विफल" है चुपचाप।
हॉट लक्स

5
@JacobKrall: C # इसे एक दोष के रूप में रिपोर्ट करेगा चाहे चेक-नेस चालू हो; सभी संगणनाएँ जिनमें केवल निरंतर अभिव्यक्ति होती है, स्वचालित रूप से जाँच की जाती है जब तक कि एक अनियंत्रित क्षेत्र के अंदर न हो।
एरिक लिपर्ट

54
मैं आपको StackOverflow पर "क्यों नहीं" प्रश्न पूछने से हतोत्साहित करता हूं; उन्हें जवाब देना मुश्किल है। एक "क्यों नहीं" सवाल यह निर्धारित करता है कि दुनिया को स्पष्ट रूप से एक ऐसा तरीका चाहिए जो ऐसा नहीं है, और इसके लिए एक अच्छा कारण होने की आवश्यकता है। यह धारणा लगभग कभी मान्य नहीं है। एक अधिक सटीक प्रश्न कुछ ऐसा होगा "विनिर्देश के किस खंड में बताया गया है कि निरंतर पूर्णांक अंकगणितीय गणना कैसे की जाती है?" या "जावा में पूर्णांक ओवरफ़्लो कैसे संभाला जाता है?"
एरिक लिपर्ट

जवाबों:


233

उस कथन में कुछ भी गलत नहीं है; आप सिर्फ 4 संख्याओं को गुणा कर रहे हैं और इसे एक इंट को सौंप रहे हैं, बस एक अतिप्रवाह होता है। यह एकल शाब्दिक असाइन करने से अलग है , जिसे संकलन-समय पर चेक किया जाएगा।

यह आउट-ऑफ-बाउंड्स शाब्दिक है जो त्रुटि का कारण बनता है, असाइनमेंट नहीं :

System.out.println(2147483648);        // error
System.out.println(2147483647 + 1);    // no error

इसके विपरीत एक longशाब्दिक ठीक संकलन होगा:

System.out.println(2147483648L);       // no error

ध्यान दें कि, वास्तव में, परिणाम है अभी भी संकलन समय पर गणना की है, क्योंकि 1024 * 1024 * 1024 * 1024एक है निरंतर अभिव्यक्ति :

int i = 1024 * 1024 * 1024 * 1024;

हो जाता है:

   0: iconst_0      
   1: istore_1      

ध्यान दें कि परिणाम ( 0) केवल लोड और संग्रहीत है, और कोई गुणन नहीं होता है।


से JLS §3.10.1 (टिप्पणी में इसे लाने के लिए @ChrisK करने के लिए धन्यवाद):

यह एक संकलित समय त्रुटि है यदि प्रकार intका एक दशमलव शाब्दिक 2147483648(2 31 ) से बड़ा है , या यदि दशमलव शाब्दिक एकात्मक2147483648 ऋण ऑपरेटर के संचालक ( §15.15.4 ) के रूप में इसके अलावा कहीं भी दिखाई देता है ।


12
और गुणन के लिए जेएलएस कहता है, यदि एक पूर्णांक गुणन ओवरफ्लो होता है, तो परिणाम गणितीय उत्पाद के निम्न-क्रम बिट्स के रूप में होता है जैसा कि कुछ पर्याप्त रूप से बड़े दो-पूरक प्रारूप में दर्शाया गया है। परिणामस्वरूप, यदि अतिप्रवाह होता है, तो परिणाम का संकेत दो ऑपरेशनल मानों के गणितीय उत्पाद के संकेत के समान नहीं हो सकता है।
क्रिस के

3
बहुत बढ़िया जवाब। कुछ लोगों को यह आभास होता है कि अतिप्रवाह किसी प्रकार की त्रुटि या विफलता है, लेकिन ऐसा नहीं है।
राउटर लीवेंस

3
@ iowatiger08 भाषा शब्दार्थ JLS द्वारा उल्लिखित है, जो JVM से स्वतंत्र है (इसलिए इससे कोई फर्क नहीं पड़ता कि आप किस JVM का उपयोग करते हैं)।
अर्शजी जू

4
@WouterLievens, अतिप्रवाह है सामान्य रूप से एक 'असामान्य' हालत, नहीं तो एक संपूर्ण त्रुटि स्थिति। यह परिमित-सटीक गणित का परिणाम है, जो ज्यादातर लोग गणित करते समय सहज रूप से होने की उम्मीद नहीं करते हैं। कुछ मामलों में, जैसे -1 + 1, यह हानिरहित है; लेकिन इसके लिए 1024^4लोगों को पूरी तरह से अप्रत्याशित परिणामों के साथ अंधा कर सकता है, जहां तक ​​वे देखने की उम्मीद करेंगे। मुझे लगता है कि उपयोगकर्ता को कम से कम एक चेतावनी या नोट होना चाहिए, और चुपचाप इसे अनदेखा न करें।
फिल पेरी

1
@ iowatiger08: int का आकार निश्चित है; यह JVM पर निर्भर नहीं करता है। जावा सी नहीं है
मार्टिन श्रोडर

43

1024 * 1024 * 1024 * 1024और 2147483648जावा में समान मूल्य नहीं है।

दरअसल, जावा में 2147483648 ISN'T EVEN A VALUE (हालाँकि 2147483648Lहै)। संकलक का शाब्दिक अर्थ नहीं है कि यह क्या है, या इसका उपयोग कैसे करना है। तो यह कराहती है।

1024जावा में एक वैध इंट है, और एक मान्य intद्वारा एक और गुणा int, हमेशा मान्य होता है int। यहां तक ​​कि अगर यह समान मूल्य नहीं है कि आप सहज रूप से उम्मीद करेंगे क्योंकि गणना अतिप्रवाह होगी।

उदाहरण

निम्नलिखित कोड नमूने पर विचार करें:

public static void main(String[] args) {
    int a = 1024;
    int b = a * a * a * a;
}

क्या आप एक संकलन त्रुटि उत्पन्न करने की अपेक्षा करेंगे? यह अब थोड़ा अधिक फिसलन हो जाता है।
क्या होगा अगर हम 3 पुनरावृत्तियों के साथ एक लूप डालते हैं और लूप में गुणा करते हैं?

कंपाइलर को ऑप्टिमाइज़ करने की अनुमति है, लेकिन यह ऐसा करते समय प्रोग्राम के व्यवहार को बदल नहीं सकता है।


यह मामला वास्तव में कैसे संभाला जाता है, इस पर कुछ जानकारी:

जावा और कई अन्य भाषाओं में, पूर्णांक बिट्स की एक निश्चित संख्या से युक्त होंगे। गणना जो कि दी गई संख्या में फिट नहीं होती है, अतिप्रवाह होगी ; गणना को मूल रूप से जावा में मापांक 2 ^ 32 किया जाता है, जिसके बाद मान वापस हस्ताक्षरित पूर्णांक में परिवर्तित हो जाता है ।

अन्य भाषाओं या एपीआई बिट्स ( BigIntegerजावा में) की एक गतिशील संख्या का उपयोग करते हैं , एक अपवाद को बढ़ाते हैं या मूल्य को एक जादुई मूल्य जैसे कि-न-एक संख्या निर्धारित करते हैं।


8
मेरे लिए, आपका कथन, " 2147483648ISN'T EVEN A VALUE (यद्यपि 2147483648Lहै)," वास्तव में उस बिंदु को पुख्ता किया जो @arshajii बनाने की कोशिश कर रहा था।
kdbanman

आह, माफ करना, हाँ, वह मैं था। मुझे आपके उत्तर में धारणा ओवरफ्लो / मॉड्यूलर अंकगणित याद आ रही थी। ध्यान दें कि यदि आप मेरे संपादन से सहमत नहीं हैं तो आप वापस रोल कर सकते हैं।
मार्टन बोडेवेस

@owlstead आपका संपादन तथ्यात्मक रूप से सही है। इसे शामिल न करने का मेरा कारण यह था कि: चाहे जो 1024 * 1024 * 1024 * 1024भी संभाला जाए मैं वास्तव में इस बात पर जोर देना चाहता था कि यह लेखन जैसी ही चीज नहीं है 2147473648। कई तरीके हैं (और आपने कुछ सूचीबद्ध किए हैं) जो एक भाषा संभावित रूप से इससे निपट सकती है। यह यथोचित रूप से अलग, और उपयोगी है। तो मैं इसे छोड़ दूंगा। जब आप किसी लोकप्रिय प्रश्न पर उच्च रैंक का उत्तर देते हैं तो बहुत सारी जानकारी आवश्यक हो जाती है।
क्रंचर

16

मुझे नहीं पता कि दूसरा संस्करण कोई त्रुटि क्यों पैदा करता है।

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

जावा के लिए, उस सूची में एक या अधिक चीजें नहीं हुईं, और इसलिए आपके पास सुविधा नहीं है। मैं नहीं जानता कि कौन सा; आपको जावा डिजाइनर पूछना होगा।

C # के लिए, उन सभी चीजों को हुआ - लगभग चौदह साल पहले - और इसलिए C # में इसी कार्यक्रम ने C # 1.0 के बाद से एक त्रुटि उत्पन्न की है।


45
यह मददगार कुछ भी नहीं जोड़ता है। जबकि मुझे जावा में स्टैब्स लेने में कोई आपत्ति नहीं है, लेकिन इसने ओपी प्रश्न का बिल्कुल भी जवाब नहीं दिया।
सियारिया

29
@ सीरिया: मूल पोस्टर एक "क्यों नहीं?" सवाल - "दुनिया ऐसा क्यों नहीं है जैसा मुझे लगता है कि यह होना चाहिए?" वास्तविक कोड के बारे में एक सटीक तकनीकी सवाल नहीं है , और इसलिए यह StackOverflow के लिए एक बुरा सवाल है। तथ्य यह है कि एक अस्पष्ट और गैर-शाब्दिक प्रश्न का सही उत्तर अस्पष्ट है और गैर-तकनीकी को अनिश्चित होना चाहिए। मैं एक बेहतर सवाल पूछने के लिए मूल पोस्टर को प्रोत्साहित करता हूं, और "क्यों नहीं?" प्रशन।
एरिक लिपर्ट

18
@ सियारिया: स्वीकृत उत्तर I नोट भी इस अस्पष्ट और गैर-तकनीकी प्रश्न का उत्तर नहीं देता है; सवाल यह है कि "यह एक त्रुटि क्यों नहीं है?" और स्वीकृत उत्तर "क्योंकि यह कानूनी है"। यह बस सवाल को बहाल कर रहा है ; जवाब "आकाश हरा क्यों नहीं है?" "क्योंकि यह नीला है" सवाल का जवाब नहीं देता है। लेकिन चूंकि प्रश्न एक बुरा प्रश्न है, मैं उत्तर देने वाले को दोष नहीं देता; जवाब एक खराब सवाल का पूरी तरह से उचित जवाब है।
एरिक लिपर्ट

13
श्री एरिक, यह वह प्रश्न है जो मैंने पोस्ट किया है: "ग्रहण में त्रुटि रिपोर्ट के बिना i = 1024 * 1024 * 1024 * 1024 क्यों?"। और अर्शजी का उत्तर ठीक वही है जो मैं (शायद अधिक)। कभी-कभी मैं किसी भी प्रश्न को बहुत सटीक तरीके से व्यक्त नहीं कर सकता। मुझे लगता है कि यही वजह है कि कुछ लोग कुछ पोस्ट किए गए सवालों को स्टैकओवरफ़्लो में अधिक सटीक रूप से संशोधित करते हैं। मुझे लगता है कि अगर मुझे जवाब चाहिए "क्योंकि यह कानूनी है", तो मैं इस प्रश्न को पोस्ट नहीं करूंगा। मैं कुछ "नियमित प्रश्न" पोस्ट करने की पूरी कोशिश करूंगा, लेकिन कृपया मेरे जैसे किसी व्यक्ति को समझें जो एक छात्र है और इतना पेशेवर नहीं है। धन्यवाद।
WUJ

5
@WUJ यह उत्तर IMHO अतिरिक्त अंतर्दृष्टि और परिप्रेक्ष्य प्रदान करता है। सभी उत्तरों को पढ़ने के बाद मुझे यह उत्तर केवल उतनी ही वैधता प्रदान करने के लिए मिला जितना कि अन्य उत्तर प्रदान किए गए थे। इसके अलावा यह जागरूकता बढ़ाता है कि डेवलपर्स केवल कुछ सॉफ्टवेयर उत्पादों के कार्यान्वयनकर्ता नहीं हैं।
सॉफ्टवेयर

12

अर्शजी के जवाब के अलावा मैं एक बात और बताना चाहता हूं:

यह असाइनमेंट नहीं है जो त्रुटि का कारण बनता है लेकिन केवल शाब्दिक का उपयोग करता है । जब आप कोशिश करते हैं

long i = 2147483648;

आप देखेंगे कि यह दाहिने हाथ की त्रुटि का कारण बनता है क्योंकि दाहिने हाथ की ओर अभी भी एक- intस्तर और सीमा से बाहर है।

इसलिए int-वैल्यूज़ (और असाइनमेंट्स सहित) का संचालन बिना कंपाइल-एरर (और रनटाइम-एरर के साथ-साथ) के बिना ओवरफ्लो हो सकता है, लेकिन कंपाइलर केवल उन बड़े-बड़े शाब्दिक को हैंडल नहीं कर सकता है।


1
सही। एक इंट को लंबे समय तक असाइन करने में एक निहित कास्ट शामिल है। लेकिन मूल्य कभी भी मौजूद नहीं हो सकता है क्योंकि पहली बार डाले जाने के लिए अंतर :) :)
क्रंचर

4

A: क्योंकि यह कोई त्रुटि नहीं है।

पृष्ठभूमि: गुणन 1024 * 1024 * 1024 * 1024एक अतिप्रवाह को जन्म देगा। अतिप्रवाह एक बग अक्सर होता है। जब ओवरफ्लो होता है तो विभिन्न प्रोग्रामिंग लैंग्वेज अलग व्यवहार उत्पन्न करती हैं। उदाहरण के लिए, C और C ++ इसे हस्ताक्षरित पूर्णांक के लिए "अपरिभाषित व्यवहार" कहते हैं, और व्यवहार को अहस्ताक्षरित पूर्णांकों के रूप में परिभाषित किया जाता है (गणितीय परिणाम को जोड़ें, UINT_MAX + 1जब तक परिणाम नकारात्मक हो, UINT_MAX + 1तब तक घटाएं जब तक कि परिणाम अधिक से अधिक हो UINT_MAX)।

जावा के मामले में, यदि intमानों के साथ एक ऑपरेशन का परिणाम अनुमत सीमा में नहीं है, तो वैचारिक रूप से जावा 2 ^ 32 को जोड़ता या घटाता है जब तक कि परिणाम अनुमत सीमा में नहीं होता है। इसलिए बयान पूरी तरह से कानूनी है और त्रुटि में नहीं है। यह सिर्फ उस परिणाम का उत्पादन नहीं करता है जिसकी आपने उम्मीद की होगी।

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

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