अहस्ताक्षरित पूर्णांक अतिप्रवाह परिभाषित व्यवहार क्यों है, लेकिन हस्ताक्षरित पूर्णांक अतिप्रवाह नहीं है?


209

अहस्ताक्षरित पूर्णांक ओवरफ़्लो सी और सी ++ मानकों दोनों द्वारा अच्छी तरह से परिभाषित किया गया है। उदाहरण के लिए, C99 मानक ( §6.2.5/9) बताता है

अहस्ताक्षरित ऑपरेंड को शामिल करने वाली संगणना कभी भी because उल्लू से अधिक नहीं हो सकती है, क्योंकि परिणामी अहस्ताक्षरित पूर्णांक प्रकार द्वारा प्रतिनिधित्व नहीं किया जा सकता है कि परिणाम modulo संख्या है कि सबसे बड़ा मूल्य है कि परिणामी प्रकार द्वारा प्रतिनिधित्व किया जा सकता है की तुलना में अधिक है कम हो जाता है।

हालाँकि, पूर्णांक ओवरफ़्लो पर हस्ताक्षर करने वाले दोनों मानक अपरिभाषित व्यवहार हैं। फिर से, C99 मानक ( §3.4.3/1) से

Unde is ned व्यवहार का एक उदाहरण un ow पर पूर्णांक पर व्यवहार है

क्या इस विसंगति के लिए कोई ऐतिहासिक या (इससे भी बेहतर!) एक तकनीकी कारण है?


50
शायद इसलिए कि हस्ताक्षरित पूर्णांक का प्रतिनिधित्व करने का एक से अधिक तरीका है। कौन सा तरीका मानक में निर्दिष्ट नहीं है, कम से कम C ++ में नहीं।
जुआनकोपंजा 20

उपयोगी लिंक: en.wikipedia.org/wiki/Signed_number_repretations
Robᵩ

7
क्या कहा juanchopanza समझ में आता है। जैसा कि मैं इसे समझता हूं, एक बड़े हिस्से में मूल सी मानक मौजूदा अभ्यास को संहिताबद्ध करता है। अगर उस समय सभी कार्यान्वयन इस बात पर सहमत हुए कि "ओवरफ्लो" को क्या करना चाहिए, तो यह मानकीकृत होने का एक अच्छा कारण है। वे इस बात पर सहमत नहीं थे कि हस्ताक्षरित अतिप्रवाह क्या करना चाहिए, ताकि मानक में न मिले।

2
इसके अलावा @DavidElliman Unsign रैपपराउंड आसानी से पता लगाने योग्य ( if (a + b < a)) भी है। गुणन पर अतिप्रवाह दोनों हस्ताक्षरित और अहस्ताक्षरित प्रकारों के लिए कठिन है।

5
@DavidElliman: यह केवल एक मुद्दा नहीं है कि आप इसका पता लगा सकते हैं, बल्कि इसका परिणाम क्या है। एक हस्ताक्षर + मूल्य कार्यान्वयन में MAX_INT+1 == -0, जबकि एक दो के पूरक पर यह होगाINT_MIN
डेविड रोड्रिग्ज़ - ड्रिबीज़

जवाबों:


163

ऐतिहासिक कारण यह है कि ज्यादातर C कार्यान्वयन (कंपाइलर) ने जो भी अतिप्रवाह व्यवहार का उपयोग किया था, वह पूर्णांक प्रतिनिधित्व के साथ लागू करने के लिए सबसे आसान था। सी कार्यान्वयन आमतौर पर सीपीयू द्वारा उपयोग किए जाने वाले एक ही प्रतिनिधित्व का उपयोग करते थे - इसलिए अतिप्रवाह व्यवहार सीपीयू द्वारा उपयोग किए जाने वाले पूर्णांक प्रतिनिधित्व से होता है।

व्यवहार में, यह केवल हस्ताक्षरित मूल्यों के लिए प्रतिनिधित्व है जो कार्यान्वयन के अनुसार भिन्न हो सकते हैं: एक का पूरक, दो का पूरक, संकेत-परिमाण। एक अहस्ताक्षरित प्रकार के लिए मानक में भिन्नता की अनुमति देने का कोई कारण नहीं है क्योंकि केवल एक स्पष्ट द्विआधारी प्रतिनिधित्व है (मानक केवल द्विआधारी प्रतिनिधित्व की अनुमति देता है)।

प्रासंगिक उद्धरण:

C99 6.2.6.1:3 :

अहस्ताक्षरित बिट-फ़ील्ड में संग्रहीत मान और टाइप किए गए चार्ट की वस्तुओं को शुद्ध बाइनरी नोटेशन का उपयोग करके दर्शाया जाएगा।

C99 6.2.6.2:2 :

यदि साइन बिट एक है, तो मूल्य निम्न तरीकों में से एक में संशोधित किया जाएगा:

- साइन बिट 0 के साथ संबंधित मान नकारात्मक ( संकेत और परिमाण ) है;

- साइन बिट का मूल्य है - (2 एन ) ( दो का पूरक );

- साइन बिट का मूल्य है - (2 एन - 1) ( किसी का पूरक )।


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


6
हालांकि, यहां महत्वपूर्ण नोट यह है कि आधुनिक दुनिया में 2 के पूरक हस्ताक्षरित अंकगणित के अलावा किसी अन्य चीज का उपयोग करने वाले कोई भी आर्किटेक्चर नहीं हैं । भाषा के मानक अभी भी कार्यान्वयन के लिए अनुमति देते हैं उदाहरण के लिए एक पीडीपी -1 एक शुद्ध ऐतिहासिक कलाकृति है।
एंडी रॉस

9
@AndyRoss लेकिन अभी भी सिस्टम (OS + संकलक, एक पुराने इतिहास के साथ
संयुक्त

3
@ और रॉस क्या आप "नो आर्किटेक्चर ... 2 के सप्लीमेंट के अलावा किसी और चीज का उपयोग करने पर विचार करेंगे ..." में आज डीएसपी और एम्बेडेड प्रोसेसर का सरगम ​​शामिल है?
chux -

11
@AndyRoss: जबकि 2s सप्लीमेंट ("नहीं" की कुछ परिभाषा के लिए) के अलावा कुछ भी उपयोग करने वाले "नहीं" आर्किटेक्चर हैं, निश्चित रूप से डीएसपी आर्किटेक्चर हैं जो हस्ताक्षर किए गए पूर्णांक के लिए संतृप्त अंकगणित का उपयोग करते हैं।
स्टीफन कैनन

10
हस्ताक्षरित अंकगणित को संतृप्त करना निश्चित रूप से मानक के अनुरूप है। बेशक रैपिंग निर्देशों का उपयोग अहस्ताक्षरित अंकगणित के लिए किया जाना चाहिए, लेकिन संकलक को हमेशा यह जानने की जानकारी होती है कि क्या अहस्ताक्षरित या हस्ताक्षरित अंकगणित किया जा रहा है, इसलिए यह निश्चित रूप से निर्देशों का उचित रूप से चयन कर सकता है।
कैफे

15

पास्कल के अच्छे उत्तर के अलावा (जो मुझे यकीन है कि मुख्य प्रेरणा है), यह भी संभव है कि कुछ प्रोसेसर हस्ताक्षर किए गए पूर्णांक अतिप्रवाह पर एक अपवाद का कारण बनते हैं, जो संकलक को "दूसरे व्यवहार की व्यवस्था" करने पर समस्याएँ पैदा करेगा (डी) उदाहरण के लिए संभावित ओवरफ्लो की जांच करने और उस मामले में अलग तरीके से गणना करने के लिए अतिरिक्त निर्देशों का उपयोग करें)।

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


23
कंपाइलर नहीं चाहते हैं कि आप उन पर सही काम करने के लिए भरोसा करें, हालांकि, और जैसे ही आप int f(int x) { return x+1>x; }अनुकूलन के लिए संकलन करते हैं , उनमें से अधिकांश आपको दिखाएंगे । जीसीसी और आईसीसी, डिफ़ॉल्ट विकल्पों के साथ, ऊपर का अनुकूलन करते हैं return 1;
पास्कल क्यूक

1
intअनुकूलन स्तर के आधार पर अतिप्रवाह के साथ सामना करने पर विभिन्न परिणाम देने वाले एक उदाहरण कार्यक्रम के लिए , देखें ideone.com/cki8nM मुझे लगता है कि यह दर्शाता है कि आपका उत्तर बुरी सलाह देता है।
मैग्नस हॉफ

मैंने उस हिस्से में थोड़ा संशोधन किया है।
मैट पीटरसन

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

1
कंपाइलर को सही ढंग से काम करने के लिए नकारात्मक मानों का अस्तित्व और "काम" करने की आवश्यकता है, यह निश्चित रूप से एक प्रोसेसर के भीतर हस्ताक्षरित मूल्यों की कमी के आसपास काम करना संभव है, और अहस्ताक्षरित मूल्यों का उपयोग करते हैं, या तो पूरक या ट्विस पूरक के रूप में, जो भी सबसे अधिक बनाता है। निर्देश सेट क्या है पर आधारित है। यह आमतौर पर इसके लिए हार्डवेयर समर्थन होने की तुलना में काफी धीमा होगा, लेकिन यह प्रोसेसर से अलग नहीं है जो हार्डवेयर में फ्लोटिंग पॉइंट का समर्थन नहीं करता है, या समान - यह सिर्फ बहुत सारे अतिरिक्त कोड जोड़ता है।
मैट पीटरसन

10

सबसे पहले, कृपया ध्यान दें कि C11 3.4.3, सभी उदाहरणों और पैरों के नोटों की तरह, मानक पाठ नहीं है और इसलिए यह हवाला देने के लिए प्रासंगिक नहीं है!

प्रासंगिक पाठ जो बताता है कि पूर्णांक और फ़्लोट का अतिप्रवाह अपरिभाषित व्यवहार है:

C11 6.5 / 5

यदि एक अभिव्यक्ति के मूल्यांकन के दौरान एक असाधारण स्थिति होती है (अर्थात, यदि परिणाम गणितीय रूप से परिभाषित नहीं है या अपने प्रकार के लिए प्रतिनिधित्व योग्य मूल्यों की सीमा में नहीं है), तो व्यवहार अपरिभाषित है।

अहस्ताक्षरित पूर्णांक प्रकारों के व्यवहार के बारे में स्पष्टीकरण यहाँ पाया जा सकता है:

C11 6.2.5 / 9

एक हस्ताक्षरित पूर्णांक प्रकार के nonnegative मानों की सीमा संगत अहस्ताक्षरित पूर्णांक प्रकार की एक सबरेंज है, और प्रत्येक प्रकार में समान मूल्य का प्रतिनिधित्व समान है। अहस्ताक्षरित ऑपरेंड को शामिल करने वाली संगणना कभी भी ओवरफ्लो नहीं हो सकती है, क्योंकि परिणामी अहस्ताक्षरित पूर्णांक प्रकार द्वारा प्रतिनिधित्व नहीं किया जा सकता है, इसलिए मॉडुलो की संख्या कम हो जाती है जो कि सबसे बड़े मूल्य से अधिक है जिसे परिणामी प्रकार द्वारा दर्शाया जा सकता है।

यह अहस्ताक्षरित पूर्णांक प्रकार को एक विशेष मामला बनाता है।

यह भी ध्यान दें कि कोई अपवाद है यदि किसी प्रकार को एक हस्ताक्षरित प्रकार में परिवर्तित किया जाता है और पुराने मूल्य का प्रतिनिधित्व नहीं किया जा सकता है। व्यवहार तो केवल कार्यान्वयन-परिभाषित है, हालांकि एक संकेत उठाया जा सकता है।

C11 6.3.1.3

6.3.1.3 हस्ताक्षरित और अहस्ताक्षरित पूर्णांक

जब पूर्णांक प्रकार के साथ एक मान _Bool के अलावा किसी अन्य पूर्णांक प्रकार में परिवर्तित हो जाता है, यदि मान को नए प्रकार से दर्शाया जा सकता है, तो यह अपरिवर्तित है।

अन्यथा, यदि नया प्रकार अहस्ताक्षरित है, तो मूल्य बार-बार जोड़कर या घटाकर अधिकतम मूल्य से एक बार घटाया जाता है जिसे नए प्रकार में तब तक प्रस्तुत किया जा सकता है जब तक कि मूल्य नए प्रकार की सीमा में न हो।

अन्यथा, नए प्रकार पर हस्ताक्षर किए गए हैं और इसमें मूल्य का प्रतिनिधित्व नहीं किया जा सकता है; या तो परिणाम कार्यान्वयन-परिभाषित है या कार्यान्वयन-परिभाषित संकेत उठाया जाता है।


6

उल्लिखित अन्य मुद्दों के अलावा, अहस्ताक्षरित गणित रैप होने से अहस्ताक्षरित पूर्णांक प्रकार अमूर्त बीजगणितीय समूहों के रूप में व्यवहार करते हैं (जिसका अर्थ है, अन्य बातों के अलावा, मूल्यों की किसी भी जोड़ी के लिए Xऔर Y, कुछ अन्य मूल्य मौजूद होंगे Zजैसे कि X+Z, यदि डाली जाए तो , बराबर Yऔर Y-Zइच्छाशक्ति, अगर ठीक से डाली जाती है, बराबरX)। यदि अहस्ताक्षरित मान केवल भंडारण-स्थान प्रकार थे और मध्यवर्ती-अभिव्यक्ति प्रकार नहीं थे (जैसे कि अगर सबसे बड़े पूर्णांक प्रकार के कोई अहस्ताक्षरित समकक्ष नहीं थे, और अहस्ताक्षरित प्रकारों पर अंकगणितीय संचालन का व्यवहार किया गया था, क्योंकि वे पहले उन्हें बड़े हस्ताक्षरित प्रकारों में बदल दिया गया था, फिर वहाँ परिभाषित रैपिंग व्यवहार के लिए उतनी ज़रूरत नहीं होगी, लेकिन एक प्रकार में गणना करना मुश्किल है, जिसमें कोई जोड़ नहीं है।

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


मैं काफी फॉलो नहीं करता - यह एडिटिव इनवर्स होने में मदद क्यों करता है? मैं वास्तव में किसी भी स्थिति के बारे में नहीं सोच सकता, जहां अतिप्रवाह व्यवहार वास्तव में उपयोगी है ...
sleske

@ साल्सके: मानव-पठनीयता के लिए दशमलव का उपयोग करते हुए, यदि कोई ऊर्जा मीटर 0003 पढ़ता है और पिछली रीडिंग 9995 थी, तो क्या इसका मतलब है कि -9992 यूनिट ऊर्जा का उपयोग किया गया था, या कि 0008 यूनिट ऊर्जा का उपयोग किया गया था? 0003-9995 की उपज 0008 होने से बाद के परिणाम की गणना करना आसान हो जाता है। उपज -9992 होने से यह थोड़ा और अजीब हो जाएगा। नहीं, सूचना है कि यह कम है, है, यह है या तो, तथापि, यह आवश्यक 9995 को 0003 की तुलना करने बनाना होगा है रिवर्स घटाव कर 9999 के परिणाम स्वरूप घटाना, और जोड़ने 1. करने में सक्षम होने
supercat

@ स्लेस्क: यह मनुष्यों और संकलक दोनों के लिए भी बहुत उपयोगी है कि वे अभिव्यक्तियों को फिर से लिखने और उन्हें सरल बनाने के लिए अंकगणित के साहचर्य, वितरण, और स्मारक कानूनों को लागू करने में सक्षम हों; उदाहरण के लिए, यदि अभिव्यक्ति a+b-cएक लूप के भीतर गणना की जाती है, bऔर cउस लूप के भीतर स्थिर होती है, तो यह लूप के (b-c)बाहर गणना को स्थानांतरित करने में मददगार हो सकती है , लेकिन ऐसा करने के लिए अन्य चीजों के बीच की आवश्यकता होती है (b-c)जो एक मूल्य प्राप्त करते हैं, जो जब जोड़ा जाता है a, उपज a+b-c, जो बदले में cएक योजक व्युत्क्रम की आवश्यकता होती है ।
सुपरकैट

: स्पष्टीकरण के लिए धन्यवाद। अगर मैं इसे सही ढंग से समझूं, तो आपके उदाहरण सभी मानते हैं कि आप वास्तव में अतिप्रवाह को संभालना चाहते हैं। ज्यादातर मामलों में मैंने सामना किया है, अतिप्रवाह अवांछनीय है, और आप इसे रोकना चाहते हैं, क्योंकि अतिप्रवाह के साथ गणना का परिणाम उपयोगी नहीं है। उदाहरण के लिए, ऊर्जा मीटर के लिए आप शायद एक ऐसे प्रकार का उपयोग करना चाहते हैं जो अतिप्रवाह कभी नहीं होता है।
sleske

1
... इस तरह कि यह (a+b)-cबराबर है a+(b-c)कि क्या अंकगणित का मूल्य b-cप्रकार के भीतर प्रतिनिधित्व करने योग्य है या नहीं , इसके लिए मूल्यों की संभावित सीमा की परवाह किए बिना प्रतिस्थापन मान्य होगा (b-c)
सुपरकैट

1

शायद अहस्ताक्षरित अंकगणित को परिभाषित करने का एक और कारण यह है कि अहस्ताक्षरित संख्याएं पूर्णांक modulo 2 ^ n का निर्माण करती हैं, जहां n अहस्ताक्षरित संख्या की चौड़ाई है। बिना अंक वाली संख्याएं केवल दशमलव अंकों के बजाय द्विआधारी अंकों का उपयोग करके पूर्णांक हैं। एक मापांक प्रणाली में मानक संचालन करना अच्छी तरह से समझा जाता है।

ओपी का उद्धरण इस तथ्य को संदर्भित करता है, लेकिन इस तथ्य को भी उजागर करता है कि बाइनरी में अहस्ताक्षरित पूर्णांकों का प्रतिनिधित्व करने के लिए केवल एक, अस्पष्ट, तार्किक तरीका है। इसके विपरीत, हस्ताक्षरित संख्याओं को अक्सर दो के पूरक का उपयोग करके दर्शाया जाता है लेकिन मानक में वर्णित अन्य विकल्प संभव हैं (खंड 6.2.6.2)।

बाइनरी फॉर्मेट में दो के पूरक प्रतिनिधित्व से निश्चित संचालन को अधिक समझ में आता है। उदाहरण के लिए, ऋणात्मक संख्याओं को बढ़ाना वही है जो सकारात्मक संख्याओं (अतिप्रवाह स्थितियों के तहत उम्मीद) के लिए है। मशीन स्तर पर कुछ ऑपरेशन हस्ताक्षरित और अहस्ताक्षरित संख्याओं के लिए समान हो सकते हैं। हालाँकि, उन परिचालनों के परिणाम की व्याख्या करते समय, कुछ मामलों का कोई मतलब नहीं है - सकारात्मक और नकारात्मक अतिप्रवाह। इसके अलावा, अंतर्निहित हस्ताक्षर प्रतिनिधित्व के आधार पर अतिप्रवाह परिणाम भिन्न होते हैं।


एक क्षेत्र के लिए एक संरचना होने के लिए, योजक पहचान के अलावा संरचना के प्रत्येक तत्व का एक गुणात्मक व्युत्क्रम होना चाहिए। पूर्णांक अनुरूप एन की संरचना एन तभी होगी जब एन एक या प्राइम [एक नीचा क्षेत्र है जब एन == 1]। क्या ऐसा कुछ है जो आपको लगता है कि मैं अपने उत्तर में चूक गया हूं?
सुपरकैट

तुम सही हो। मैं प्राइम पावर मोडुली से भ्रमित हो गया। मूल प्रतिक्रिया संपादित की गई।
yth

यहां अतिरिक्त भ्रामक यह है कि ऑर्डर 2 ^ n का एक क्षेत्र है, यह पूर्णांक modulo 2 ^ n के लिए रिंग-आइसोमॉर्फिक नहीं है।
केविन वेंटुलो

और, 2 ^ 31-1 एक मेर्सेन प्राइम है (लेकिन 2 ^ 63-1 प्राइम नहीं है)। इस प्रकार, मेरा मूल विचार बर्बाद हो गया। इसके अलावा, पूर्णांक आकार दिन में अलग थे। तो, मेरा विचार सबसे अच्छा संशोधनवादी था।
yth

तथ्य यह है कि अहस्ताक्षरित पूर्णांक एक रिंग बनाते हैं (फ़ील्ड नहीं), कम-क्रम वाले हिस्से को लेने से भी एक रिंग उत्पन्न होती है, और पूरे मूल्य पर संचालन करते हैं और फिर ट्रंकटिंग केवल निचले हिस्से पर संचालन करने के बराबर व्यवहार करेगा, IMHO थे लगभग निश्चित रूप से विचार।
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.