2016-08-04 13 views
14

मुझे सी ++ में पूर्णांक विभाजन के साथ कुछ अजीब परिणाम का सामना करना पड़ रहा है। मैं इसकी गणना करने की कोशिश कर रहा हूं: -2147483648/-1सी ++ पूर्णांक विभाजन सीमा और नकारात्मक मानों के लिए कैसे काम करता है?

मुझे क्या मिलेगा है 3 विभिन्न परिदृश्यों में 3 अलग अलग परिणाम:

int foo(int numerator, int denominator) { 
    int res = numerator/denominator; // produces SIGFPE, Arithmetic exception interrupt 

    cout << res << endl; 
} 

int main() { 
    int res = -2147483648/-1; 
    cout << res << endl;    // prints -2147483648 
    cout << -2147483648/-1 << endl; // prints 2147483648 
    foo(-2147483648, -1); 
    return 0; 
} 

क्यों करता पूर्णांक विभाजन आपरेशन विभिन्न स्थितियों में अलग अलग परिणाम का उत्पादन?

+1

वर्थ का उल्लेख यह है कि कोड विंडोज वीएस-2015 पर संकलित नहीं है, 'नकारात्मक अभिन्न निरंतर निरंतर प्रकार \t' में परिवर्तित हो गया है और 'यूनरी माइनस ऑपरेटर हस्ताक्षरित प्रकार पर लागू होता है, परिणाम अभी भी हस्ताक्षरित नहीं है' सभी '-2147483648/-1' लाइनों –

+1

पर सरल उत्तर [यहां] (http://stackoverflow.com/a/29355979/1460794)। – wally

+2

इस प्रकार दृश्य स्टूडियो यह करता है: '# परिभाषित करें INT_MIN (-2147483647 - 1) // न्यूनतम (हस्ताक्षरित) int मान' – wally

उत्तर

12

शाब्दिक -2147483648/-1 कि इतना चौड़ा होता है कि मूल्य धारण करने के लिए है एक डेटा प्रकार में 2147483648 के रूप में अपने संकलक द्वारा गणना की जाती है ।

जब शाब्दिक रूप से मुद्रित किया जाता है, तो यह मूल्य को सही तरीके से प्रिंट करता है।

जब शाब्दिक res में संग्रहीत किया जाता है, तो इसे int पर डाला जाता है। एक int आपके सिस्टम पर 32 बिट चौड़ा प्रतीत होता है। मान 2147483648 को 32 बिट हस्ताक्षरित पूर्णांक के रूप में प्रदर्शित नहीं किया जा सकता है, इसलिए कास्ट एक अतिप्रवाह का कारण बनता है। आपके सिस्टम पर, इस ओवरफ़्लो के परिणाम -2147483648 (संभवतः यह दो के पूरक का उपयोग कर रहा है) में परिणाम देता है।

अंत में, जब रनटाइम पर विभाजन प्रदर्शन करने के लिए (foo समारोह में) की कोशिश कर रहा, SIGFPE अपवाद अतिप्रवाह (क्योंकि int डेटाप्रकार परिणाम का प्रतिनिधित्व नहीं कर सकते हैं) के कारण होता है।

ध्यान दें कि इन तीन विकल्पों के सभी मंच निर्भर व्यवहार पर भरोसा करते हैं:

  • तथ्य यह है कि संकलक किसी भी त्रुटि (या अन्य मुद्दों) जब शाब्दिक गणना अतिप्रवाह उत्पन्न नहीं करता है और सिर्फ एक डेटा प्रकार का उपयोग करता है इतना बड़ा परिणाम
  • तथ्य यह है कि int अतिप्रवाह जब शाब्दिक भंडारण उत्पन्न करता है धारण करने के लिए है कि विशिष्ट मूल्य (और कोई अन्य मुद्दों)
  • तथ्य यह है कि SIGFPE अपवाद फेंक दिया जाता है जब क्रम
  • पर बह निकला
+0

संकलन के दौरान AFAICT पूर्णांक ओवरफ़्लो को पूरा करता है, अनिर्धारित व्यवहार है; एक बड़े डेटाटाइप का उपयोग करना एक संभावित व्यवहार है, लेकिन फर्स्टस्टेप शो के रूप में, एक और व्यवहार त्रुटि करना है। – MSalters

+0

@MSalters: हाँ, मैं पिछले अनुच्छेद में जितना अधिक बताता हूं। –

+0

जो गलत-आश है: प्रत्येक प्लेटफ़ॉर्म को पर्याप्त विस्तृत डेटाटाइप का समर्थन करना होता है; 'लंबे समय तक int' निश्चित रूप से पर्याप्त चौड़ा है। – MSalters

12

आपका परिणाम INT_MAX+1 हो सकता है, दूसरे शब्दों में यह शायद अधिकतर बहती है। वह अपरिभाषित व्यवहार है, और कुछ भी हो सकता है। उदाहरण के लिए, एक कंपाइलर कोड को सीधे अस्वीकार कर सकता है।

(ए प्रणाली INT_MAX >= 2147483648 हो सकता है, लेकिन फिर आप अपने 3 testcases के लिए एक ही परिणाम उम्मीद करेंगे)

10
int res = -2147483648/-1; 
cout << res << endl;    // prints -2147483648 
cout << -2147483648/-1 << endl; // prints 2147483648 
int res = numerator/denominator; // produces SIGFPE, Arithmetic exception interrupt 

नोट कोई नकारात्मक integer literals नहीं है।

कोई नकारात्मक पूर्णांक अक्षर नहीं हैं। जैसे अभिव्यक्तियां -1 यूनियन माइनस ऑपरेटर को शाब्दिक द्वारा दर्शाए गए मूल्य पर लागू करती हैं, जिसमें अंतर्निहित प्रकार के रूपांतरण शामिल हो सकते हैं।

शाब्दिक 2147483648int की अधिकतम मूल्य से भी बड़ा है, तो अपने प्रकार long हो जाएगा (या long long, कार्यान्वयन पर निर्भर करता है)।फिर -2147483648 का प्रकार long है, और गणना का परिणाम (-2147483648/-1) long भी है।

1 मामले के लिए, परिणाम प्रकार long की 2147483648int को implicitly converted है, लेकिन यह int की अधिकतम मूल्य से भी बड़ा है, परिणाम कार्यान्वयन परिभाषित किया गया है। (ऐसा लगता है कि परिणाम यहां प्रतिनिधित्व (2 के पूरक) के नियमों के अनुसार लपेटा गया है, इसलिए आपको परिणाम -2147483648 मिल गया है।)

दूसरे मामले के लिए, long प्रकार के साथ परिणाम सीधे मुद्रित किया गया है, इसलिए आप सही परिणाम प्राप्त करें।

3 मामले के लिए, आप दो int रों पर गणना कर रहे हैं, और परिणाम परिणाम प्रकार (अर्थात int) में फिट नहीं कर सकते, signed integer arithmetic operation overflow हुआ, व्यवहार अनिर्धारित रहता है। (एसआईजीएफपीई, अंकगणितीय अपवाद का उत्पादन यहां बाधित है।)

+0

'-2147483648'' लंबा लंबा 'हो सकता है, उदा। एमएसवीसी पर (जिसमें 'LONG_MAX = 2147483647' है) – MSalters

+0

सीआई ++ के पुराने संस्करणों में आईआईआरसी यह 32-बिट असाइन किया गया लंबा भी हो सकता है (जो वास्तव में अंतिम परिणाम नहीं बदलता है, लेकिन यह बदलता है कि आप वहां कैसे जाते हैं)। – plugwash

+0

@plugwash मुझे "पुराने" सी ++ के बारे में बहुत कुछ पता नहीं है। :) अभी के लिए, यह 'लंबा' या 'लंबा लंबा' होगा (सी ++ 11 के बाद से), जब तक प्रत्यय 'u' का उपयोग नहीं किया जाता है तब तक यह 'हस्ताक्षरित' नहीं होगा। प्रतिनिधित्व कार्यान्वयन-परिभाषित है, इसलिए 32-बिट पूर्णांक द्वारा 'लंबा' का प्रतिनिधित्व किया जा सकता है। – songyuanyao

संबंधित मुद्दे