मैं = i + i मुझे 0 क्यों देता है?


96

मेरा एक सरल कार्यक्रम है:

public class Mathz {
    static int i = 1;
    public static void main(String[] args) {    
        while (true){
            i = i + i;
            System.out.println(i);
        }
    }
}

जब मैं इस कार्यक्रम चलाने के लिए, सब मैं देख रहा है 0के लिए iमेरी उत्पादन में। मुझे उम्मीद होगी कि पहले दौर में हमारे पास i = 1 + 1, उसके बाद i = 2 + 2, i = 4 + 4आदि होंगे।

क्या यह इस तथ्य के कारण है कि जैसे ही हम iबाएं हाथ की तरफ फिर से घोषित करने का प्रयास करते हैं , इसका मूल्य फिर से हो जाता है 0?

अगर कोई मुझे इस बात की बारीक जानकारी दे सके, तो यह बहुत अच्छा होगा।

बदले intके लिए longहै और यह संख्या मुद्रण किए जाने की संभावना के रूप में लगता है। मुझे आश्चर्य है कि यह कितनी तेजी से अधिकतम 32-बिट मूल्य हिट करता है!

जवाबों:


168

समस्या पूर्णांक अतिप्रवाह के कारण है।

32-बिट ट्वोज़-पूरक अंकगणित में:

iवास्तव में पॉवर ऑफ़ टू वैल्यू होना शुरू हो जाता है, लेकिन तब ओवरफ़्लो व्यवहार शुरू होता है जब आप 2 30 पर पहुँच जाते हैं :

2 30 + 2 30 = -2 31

-2 31 + -2 31 = 0

... intअंकगणित में, चूंकि यह अनिवार्य रूप से अंकगणित आधुनिक 2 ^ 32 है।


28
क्या आप अपने उत्तर पर थोड़ा विस्तार कर सकते हैं?
डेसीस

17
@oOTesterOo यह 2, 4 आदि की छपाई शुरू करता है, लेकिन यह बहुत जल्दी पूर्णांक के अधिकतम मूल्य तक पहुंच जाता है और यह नकारात्मक संख्याओं के लिए "चारों ओर" घूमता है, एक बार शून्य तक पहुंचने पर यह हमेशा के लिए शून्य पर रहता है
रिचर्ड टिंगल

52
इस उत्तर भी पूरा (यह भी नहीं है नहीं है उल्लेख है कि मूल्य होगा नहीं हो 0पहले कुछ पुनरावृत्तियों पर है, लेकिन उत्पादन की गति ओपी से उस तथ्य अस्पष्ट बना रहा है)। इसे क्यों स्वीकार किया जाता है?
10

16
संभवतः इसे स्वीकार कर लिया गया था क्योंकि इसे ओपी द्वारा मददगार माना गया था।
जो

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

334

परिचय

समस्या पूर्णांक अतिप्रवाह है। यदि यह ओवरफ्लो होता है, तो यह न्यूनतम मूल्य पर वापस चला जाता है और वहां से जारी रहता है। यदि यह कम हो जाता है, तो यह अधिकतम मूल्य पर वापस चला जाता है और वहां से जारी रहता है। नीचे की छवि एक ओडोमीटर की है। मैं इसका उपयोग ओवरफ्लो समझाने के लिए करता हूं। यह एक यांत्रिक अतिप्रवाह है लेकिन अभी भी एक अच्छा उदाहरण है।

एक ओडोमीटर में max digit = 9, इसलिए, अधिकतम साधनों से परे जा रहा है 9 + 1, जो कि वहन करता है और एक देता है 0; हालाँकि 1, बदलने के लिए कोई उच्च अंक नहीं है , इसलिए काउंटर को रीसेट करता है zero। आपको यह विचार आता है - "पूर्णांक ओवरफ्लो" अब मन में आता है।

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

टाइप इंट का सबसे बड़ा दशमलव शाब्दिक 2147483647 (2 31 -1) है। 0 से 2147483647 तक के सभी दशमलव शाब्दिक रूप से कहीं भी एक अंतर शाब्दिक रूप में प्रकट हो सकता है, लेकिन शाब्दिक 2147483648 केवल एक ही नेगेटिव ऑपरेटर के ऑपरेटर के रूप में प्रकट हो सकता है -।

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

इस प्रकार, 2147483647 + 1ओवरफ्लो होता है और चारों ओर लपेटता है -2147483648। इसलिए int i=2147483647 + 1अतिप्रवाह किया जाएगा, जो नहीं के बराबर है 2147483648। इसके अलावा, आप कहते हैं "यह हमेशा 0 प्रिंट करता है"। यदि ऐसा नहीं होता क्योंकि http://ideone.com/WHrQIW । नीचे, ये 8 नंबर उस बिंदु को दिखाते हैं जिस पर यह पिवोट्स और ओवरफ्लो करता है। इसके बाद 0s प्रिंट करना शुरू करता है। इसके अलावा, आश्चर्यचकित मत हो कि यह कितनी तेजी से गणना करता है, आज की मशीनें तेज हैं।

268435456
536870912
1073741824
-2147483648
0
0
0
0

क्यों पूर्णांक अतिप्रवाह "चारों ओर लपेटता है"

मूल पीडीएफ


17
मैंने प्रतीकात्मक उद्देश्यों के लिए "पैकमैन" के लिए एनीमेशन जोड़ा है, लेकिन यह एक महान दृश्य के रूप में भी काम करता है कि कोई 'पूर्णांक ओवरफ्लॉवर' कैसे देखेगा।
अली गजनी

9
यह इस साइट पर हर समय मेरा पसंदीदा जवाब है।
ली व्हाइट

2
आपको लगता है कि यह एक दोहरा अनुक्रम था, एक को जोड़ना नहीं है।
पाओलो एबरमन

2
मुझे लगता है कि पैक्मैन एनीमेशन को यह उत्तर स्वीकृत उत्तर की तुलना में अधिक उत्थान मिला। मुझ पर एक और उत्थान है - मेरे पसंदीदा खेलों में से एक!
हुसैन

3
जिस किसी को भी प्रतीक नहीं मिला: en.wikipedia.org/wiki/Kill_screen#Pac-Man
wei2912

46

नहीं, यह केवल शून्य मुद्रित नहीं करता है।

इसे इसमें बदलें और आप देखेंगे कि क्या होता है।

    int k = 50;
    while (true){
        i = i + i;
        System.out.println(i);
        k--;
        if (k<0) break;
    }

जो होता है उसे ओवरफ्लो कहा जाता है।


61
लूप के लिए लिखने का दिलचस्प तरीका :)
बर्नहार्ड

17
@ बर्नहार्ड संभवतः ओपी के कार्यक्रम की संरचना को बनाए रखना है।
तैमूर

4
@Taemyr शायद, लेकिन फिर वह :) के trueसाथ बदल सकता थाi<10000
बर्नहार्ड

7
मैं सिर्फ कुछ बयान जोड़ना चाहता था; किसी भी बयान को हटाने / बदलने के बिना। मुझे आश्चर्य है कि इसने इतना व्यापक ध्यान आकर्षित किया।
पीटर.परोव जू

18
आप छिपे हुए ऑपरेटर को while(k --> 0)बोलचाल की भाषा में "जबकि kजाता है 0";) का उपयोग कर सकते थे ;
लॉरेंट ला रिज़्ज़ा

15
static int i = 1;
    public static void main(String[] args) throws InterruptedException {
        while (true){
            i = i + i;
            System.out.println(i);
            Thread.sleep(100);
        }
    }

बाहर रखा:

2
4
8
16
32
64
...
1073741824
-2147483648
0
0

when sum > Integer.MAX_INT then assign i = 0;

4
उम, नहीं, यह केवल इस विशेष अनुक्रम को शून्य पर लाने के लिए काम करता है। 3. से शुरू करने की कोशिश करें
पाओलो एबरमन

4

चूंकि मेरे पास पर्याप्त प्रतिष्ठा नहीं है, मैं सी में एक ही प्रोग्राम के लिए आउटपुट की तस्वीर को नियंत्रित आउटपुट के साथ पोस्ट नहीं कर सकता, यू आप खुद कोशिश कर सकते हैं और देख सकते हैं कि यह वास्तव में 32 बार प्रिंट करता है और फिर अतिप्रवाह के कारण समझाया गया है = 1073741824 + 1073741824 -2147483648 में परिवर्तन और एक और अतिरिक्त अंतर की सीमा से बाहर है और बदल जाता है Zero

#include<stdio.h>
#include<conio.h>

int main()
{
static int i = 1;

    while (true){
        i = i + i;
      printf("\n%d",i);
      _getch();
    }
      return 0;
}

3
सी में यह कार्यक्रम, वास्तव में हर निष्पादन में अपरिभाषित व्यवहार को ट्रिगर करता है, जो कंपाइलर को पूरे कार्यक्रम को किसी भी चीज़ से बदलने की अनुमति देता है (यहां तक ​​कि system("deltree C:"), जब से आप डॉस / विंडोज में हैं)। हस्ताक्षरित पूर्णांक अतिप्रवाह जावा के विपरीत C / C ++ में अपरिभाषित व्यवहार है। इस तरह के निर्माण का उपयोग करते समय बहुत सावधान रहें।
फाइलबैन

@filcab: "पूरे कार्यक्रम को किसी भी चीज़ से बदलें" आप किस बारे में बात कर रहे हैं। मैंने विजुअल स्टूडियो 2012 पर इस कार्यक्रम को चलाया है और यह signed and unsignedबिना किसी अपरिभाषित व्यवहार के
Kaify

3
@ काम: ठीक काम एक पूरी तरह से वैध अपरिभाषित व्यवहार है। हालांकि कल्पना कीजिए कि कोड i += i32+ पुनरावृत्तियों के लिए किया था , तब था if (i > 0)। कंपाइलर इस बात का अनुकूलन कर सकता है कि if(true)अगर हम हमेशा पॉजिटिव नंबर जोड़ रहे हैं, iतो हमेशा 0. से अधिक होगा। यह उस स्थिति को भी छोड़ सकता है, जहां इसे निष्पादित नहीं किया जाएगा, क्योंकि यहां ओवरफ्लो का प्रतिनिधित्व किया गया है। क्योंकि कंपाइलर उस कोड से दो समान वैध प्रोग्राम तैयार कर सकता है, यह अपरिभाषित व्यवहार है।
3Doubloons

1
@Kaify: यह शाब्दिक विश्लेषण नहीं है, यह आपके कोड को संकलित करने वाला कंपाइलर है, और मानक का पालन करते हुए, "अजीब" अनुकूलन करने में सक्षम है। लूप की तरह कि 3Doubloons के बारे में बात की। सिर्फ इसलिए कि कंपाइलर जो आप हमेशा कोशिश करते हैं कि वह कुछ करते हैं, इसका मतलब यह नहीं है कि मानक गारंटी देता है कि आपका प्रोग्राम हमेशा उसी तरह से चलेगा। आपके पास अपरिभाषित व्यवहार था, कुछ कोड को समाप्त कर दिया गया हो सकता है क्योंकि वहां पहुंचने का कोई रास्ता नहीं है (यूबी गारंटी देता है)। Llvm ब्लॉग (और वहाँ लिंक) से इन पोस्टों में अधिक जानकारी है: blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
filcab

2
@Kaify: इसे नहीं डालने के लिए क्षमा करें, लेकिन "इसे गुप्त रखा" कहना पूरी तरह से गलत है, खासकर जब यह Google पर "अपरिभाषित व्यवहार" के लिए दूसरा परिणाम है, जो कि उस विशिष्ट शब्द का इस्तेमाल किया गया था जिसके लिए मुझे ट्रिगर किया जा रहा था। ।
फ़िल्मकब

4

का मूल्य iबाइनरी अंकों की एक निश्चित मात्रा का उपयोग कर स्मृति में संग्रहीत किया जाता है। जब किसी संख्या को उपलब्ध होने की तुलना में अधिक अंकों की आवश्यकता होती है, तो केवल सबसे कम अंक संग्रहीत होते हैं (उच्चतम अंक खो जाते हैं)।

iस्वयं को जोड़ना iदो से गुणा करना समान है । जैसे दशमलव संकेतन में संख्या को दस से गुणा करने पर प्रत्येक अंक को बाईं ओर खिसका कर और दाएं पर शून्य लगाकर, संख्या को बाइनरी अंकन में दो से गुणा करके उसी तरह से प्रदर्शन किया जा सकता है। यह दाईं ओर एक अंक जोड़ता है, इसलिए बाईं ओर एक अंक खो जाता है।

यहां शुरुआती मूल्य 1 है, इसलिए यदि हम स्टोर करने के लिए 8 अंकों का उपयोग करते हैं i(उदाहरण के लिए),

  • 0 पुनरावृत्तियों के बाद, मान है 00000001
  • 1 पुनरावृत्ति के बाद, मान है 00000010
  • 2 पुनरावृत्तियों के बाद, मान है 00000100

और इतने पर, अंतिम गैर-शून्य चरण तक

  • 7 पुनरावृत्तियों के बाद, मान है 10000000
  • 8 पुनरावृत्तियों के बाद, मान है 00000000

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


3

यह सही है, लेकिन 31 पुनरावृत्तियों के बाद, 1073741824 + 1073741824 सही ढंग से गणना नहीं करते हैं और उसके बाद केवल 0 प्रिंट करते हैं।

आप BigInteger का उपयोग करने के लिए रिफ्लेक्टर कर सकते हैं, इसलिए आपका अनंत लूप सही तरीके से काम करेगा।

public class Mathz {
    static BigInteger i = new BigInteger("1");

    public static void main(String[] args) {    

        while (true){
            i = i.add(i);
            System.out.println(i);
        }
    }
}

यदि मैं इंट के बजाय लंबे का उपयोग करता हूं, तो यह लंबे समय तक प्रिंट> 0 नंबर लगता है। 63 पुनरावृत्तियों के बाद यह इस समस्या में क्यों नहीं चलता है?
डेसीस

1
"सही ढंग से गणना नहीं करता है" एक गलत लक्षण वर्णन है। जावा अनुमान के अनुसार गणना सही है। असली मुद्दा यह है कि (आदर्श) गणना के परिणाम का प्रतिनिधित्व नहीं किया जा सकता है int
स्टीफन सी

@ootesterOo - क्योंकि longबड़ी संख्या का प्रतिनिधित्व intकर सकते हैं।
स्टीफन सी

लंबी एक बड़ी रेंज है। BigInteger किसी भी मान / लंबाई को स्वीकार करता है जिसे आपका JVM आवंटित कर सकता है।
ब्रूनो वोल्पाटो

मैंने 31 पुनरावृत्तियों के बाद int overflows ग्रहण किया क्योंकि इसकी 32-बिट अधिकतम आकार की संख्या है, और इतने लंबे समय तक जो 64-बिट 63 के बाद इसकी अधिकतम हिट होगी? ऐसा क्यों नहीं है?
डेसीस

2

ऐसे मामलों को डीबग करने के लिए लूप में पुनरावृत्तियों की संख्या को कम करना अच्छा है। अपने के बजाय इसका उपयोग करें while(true):

for(int r = 0; r<100; r++)

फिर आप देख सकते हैं कि यह 2 से शुरू होता है और मूल्य को दोगुना कर रहा है जब तक कि यह एक अतिप्रवाह पैदा नहीं कर रहा है।


2

मैं चित्रण के लिए 8-बिट संख्या का उपयोग करूंगा क्योंकि यह एक छोटी जगह में पूरी तरह से विस्तृत हो सकता है। हेक्स संख्या 0x से शुरू होती है, जबकि बाइनरी संख्या 0 बी से शुरू होती है।

8-बिट अहस्ताक्षरित पूर्णांक के लिए अधिकतम मान 255 (0xFF या 0b11111111) है। यदि आप 1 जोड़ते हैं, तो आप आमतौर पर प्राप्त करने की उम्मीद करेंगे: 256 (0x100 या 0b100000000)। लेकिन चूंकि यह बहुत अधिक बिट्स (9) है, जो कि अधिकतम से अधिक है, इसलिए पहला भाग सिर्फ गिरा हुआ है, आपको 0 प्रभावी रूप से छोड़ रहा है (0x (1) 00 या 0b (1) 00000000, लेकिन 1 गिरा)।

इसलिए जब आपका कार्यक्रम चलता है, तो आप मिलते हैं:

1 = 0x01 = 0b1
2 = 0x02 = 0b10
4 = 0x04 = 0b100
8 = 0x08 = 0b1000
16 = 0x10 = 0b10000
32 = 0x20 = 0b100000
64 = 0x40 = 0b1000000
128 = 0x80 = 0b10000000
256 = 0x00 = 0b00000000 (wraps to 0)
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
...

1

2147483648 (= 2 31 ) प्रकार intका सबसे बड़ा दशमलव शाब्दिक है । 0 से 2147483647 तक के सभी दशमलव शाब्दिक रूप से कहीं भी एक अंतर शाब्दिक रूप में प्रकट हो सकता है, लेकिन शाब्दिक 2147483648 केवल एक ही नेगेटिव ऑपरेटर के ऑपरेटर के रूप में प्रकट हो सकता है -।

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

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