क्या अहस्ताक्षरित पूर्णांक घटाव परिभाषित व्यवहार है?


100

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

unsigned int To, Tf;

To = getcounter();
while (1) {
    Tf = getcounter();
    if ((Tf-To) >= TIME_LIMIT) {
        break;
    } 
}

यह सी मानक से केवल वही प्रासंगिक उद्धरण है जो मुझे मिल सकता है।

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

मुझे लगता है कि कोई यह कहने का मतलब निकाल सकता है कि जब सही ऑपरेंड बड़ा होता है तो ऑपरेशन को मोडुलो ट्रंकेटेड नंबरों के संदर्भ में सार्थक होने के लिए समायोजित किया जाता है।

अर्थात

0x0000 - 0x0001 == 0x 1 0000 - 0x0001 == 0xFFFF

कार्यान्वयन आश्रित हस्ताक्षरित शब्दार्थ का उपयोग करने के विरोध में:

0x0000 - 0x0001 == (अहस्ताक्षरित) (0 + -1) == (0xFFFF लेकिन साथ ही 0xFFFE या 0x8001)

कौन सी या कौन सी व्याख्या सही है? क्या यह बिल्कुल भी परिभाषित है?


3
मानक में शब्दों का चुनाव दुर्भाग्यपूर्ण है। कि यह "कभी भी अतिप्रवाह नहीं हो सकता" का अर्थ है कि यह एक त्रुटि स्थिति नहीं है। वैल्यू को ओवरफ्लो करने के बजाय मानक में शब्दावली का उपयोग करना "लपेटता है।"
डैनोर्टन

जवाबों:


107

एक अनिर्दिष्ट प्रकार में एक ऋणात्मक संख्या उत्पन्न करने वाले घटाव का परिणाम अच्छी तरह से परिभाषित है:

  1. [...] अहस्ताक्षरित ऑपरेंड को शामिल करने वाली संगणना कभी भी ओवरफ्लो नहीं हो सकती है, क्योंकि परिणामी अहस्ताक्षरित पूर्णांक प्रकार का प्रतिनिधित्व नहीं किया जा सकता है, इसलिए उस संख्या को कम कर दिया जाता है जो उस संख्या के सबसे बड़े मान से अधिक है जिसे परिणामी प्रकार द्वारा दर्शाया जा सकता है। (आईएसओ / आईईसी 9899: 1999 (ई) .56.2.5 / 9)

जैसा कि आप देख सकते हैं, (unsigned)0 - (unsigned)1-1 modulo UINT_MAX + 1 के बराबर है, या दूसरे शब्दों में, UINT_MAX।

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


2
धन्यवाद! अब मुझे वह व्याख्या दिखाई दे रही है जो मुझे याद आ रही थी। मुझे लगता है कि वे हालांकि एक स्पष्ट शब्दों को चुन सकते थे।

4
मैं इतना बेहतर अब लग रहा है, जानते हुए भी कि अगर शून्य करने के लिए किसी भी अहस्ताक्षरित अलावा रोल के आसपास है और हिंसा का कारण बनता है, क्योंकि हो जाएगा uintहमेशा गणितीय प्रतिनिधित्व करने का इरादा था अंगूठी पूर्णांक 0के माध्यम से UINT_MAXइसके अलावा और गुणा सापेक्ष के संचालन के साथ, UINT_MAX+1है, और क्योंकि नहीं एक अतिप्रवाह की। हालाँकि, यह इस बात का प्रश्न है कि यदि रिंग ऐसे मौलिक डेटा प्रकार हैं, तो भाषा अन्य आकारों के रिंगों के लिए अधिक सामान्य समर्थन प्रदान नहीं करती है।
थियोडोर मर्डॉक

2
@ TheodoreMurdock मुझे लगता है कि प्रश्न का उत्तर सरल है। जहां तक ​​मैं बता सकता हूं, यह तथ्य है कि यह एक परिणाम है, एक कारण नहीं है। वास्तविक आवश्यकता यह है कि अहस्ताक्षरित प्रकारों के मूल्य प्रतिनिधित्व में भाग लेने वाले उनके सभी बिट्स होने चाहिए। अंगूठी जैसा व्यवहार स्वाभाविक रूप से उसी से बहता है। यदि आप अन्य प्रकारों से ऐसा व्यवहार चाहते हैं, तो अपने अंकगणित को आवश्यक मापांक लागू करने के बाद करें; यह मौलिक ऑपरेटरों का उपयोग करता है।
अंडरस्कोर_ड

@underscore_d बेशक ... यह स्पष्ट है कि उन्होंने डिजाइन का निर्णय क्यों लिया। यह केवल मनोरंजक है कि उन्होंने कल्पना की है कि मोटे तौर पर "वहाँ कोई अंकगणित नहीं है / नीचे की ओर क्योंकि डेटा प्रकार एक अंगूठी के रूप में कल्पना है", जैसे कि इस डिजाइन विकल्प का मतलब है कि प्रोग्रामर को सावधानी से और इसके तहत बचने की ज़रूरत नहीं है -प्रवाह या उनके कार्यक्रम शानदार रूप से विफल होते हैं।
थियोडोर मर्डॉक

120

जब आप अहस्ताक्षरित प्रकारों के साथ काम करते हैं, तो मॉड्यूलर अंकगणित (जिसे "रैप अराउंड" व्यवहार के रूप में भी जाना जाता है) हो रहा है। इस मॉड्यूलर अंकगणित को समझने के लिए , बस इन घड़ियों पर एक नज़र:

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

9 + 4 = 1 ( 13 मॉड 12 ), इसलिए दूसरी दिशा में यह है: 1 - 4 = 9 ( -3 मॉड 12 )। अहस्ताक्षरित प्रकारों के साथ काम करते समय एक ही सिद्धांत लागू किया जाता है। यदि परिणाम प्रकार है unsigned, तो मॉड्यूलर अंकगणित होता है।


अब निम्नलिखित कार्यों को एक परिणाम के रूप में देखें unsigned int:

unsigned int five = 5, seven = 7;
unsigned int a = five - seven;      // a = (-2 % 2^32) = 4294967294 

int one = 1, six = 6;
unsigned int b = one - six;         // b = (-5 % 2^32) = 4294967291

जब आप यह सुनिश्चित करना चाहते हैं कि परिणाम क्या है signed, तो इसे signedचर में संग्रहीत करें या इसे कास्ट करें signed। जब आप संख्याओं के बीच अंतर प्राप्त करना चाहते हैं और सुनिश्चित करें कि मॉड्यूलर अंकगणितीय लागू नहीं किया जाएगा, तो आपको abs()निम्न में परिभाषित फ़ंक्शन का उपयोग करने पर विचार करना चाहिए stdlib.h:

int c = five - seven;       // c = -2
int d = abs(five - seven);  // d =  2

बहुत सावधानी बरतें, खासकर जब लेखन की स्थिति, क्योंकि:

if (abs(five - seven) < seven)  // = if (2 < 7)
    // ...

if (five - seven < -1)          // = if (-2 < -1)
    // ...

if (one - six < 1)              // = if (-5 < 1)
    // ...

if ((int)(five - seven) < 1)    // = if (-2 < 1)
    // ...

परंतु

if (five - seven < 1)   // = if ((unsigned int)-2 < 1) = if (4294967294 < 1)
    // ...

if (one - six < five)   // = if ((unsigned int)-5 < 5) = if (4294967291 < 5)
    // ...

4
घड़ियों के साथ अच्छा है, हालांकि सबूत यह सही जवाब देगा। प्रश्न के आधार में पहले से ही यह दावा शामिल है कि यह सब सच हो सकता है।
को ऑर्बिट में

5
@LightnessRacesinOrbit: धन्यवाद। मैंने इसे लिखा क्योंकि मुझे लगता है कि किसी को यह बहुत मददगार लग सकता है। मैं सहमत हूं, कि यह पूर्ण उत्तर नहीं है।
18

4
लाइन int d = abs(five - seven);अच्छी नहीं है। पहले five - sevenगणना की जाती है: पदोन्नति ऑपरेंड प्रकारों को छोड़ देती है unsigned int, परिणाम की गणना मॉडुलो के रूप में की जाती है (UINT_MAX+1), और इसका मूल्यांकन करता है UINT_MAX-1। फिर यह मान वास्तविक पैरामीटर है abs, जो बुरी खबर है। abs(int)तर्क को पारित करने के लिए अपरिभाषित व्यवहार का कारण बनता है, क्योंकि यह सीमा में नहीं है, और abs(long long)शायद मूल्य पकड़ सकता है, लेकिन अपरिभाषित व्यवहार तब होता है जब वापसी मूल्य intको आरंभीकृत करने के लिए मजबूर किया जाता है d
बेन वोइगट

1
@ लियो: सी ++ में एकमात्र ऑपरेटर जो संदर्भ-संवेदनशील है और इसके परिणाम का उपयोग कैसे किया जाता है, इसके आधार पर अलग-अलग तरीके से कार्य करता है, यह एक कस्टम रूपांतरण ऑपरेटर है operator T()। जिन दो अभिव्यक्तियों पर हम चर्चा कर रहे हैं उनमें जोड़ unsigned int, ऑपरेंड प्रकारों के आधार पर टाइप में किया जाता है । जोड़ का परिणाम है unsigned int। फिर उस परिणाम को संक्षेप में संदर्भ में आवश्यक प्रकार में बदल दिया जाता है, एक रूपांतरण जो विफल हो जाता है क्योंकि मूल्य नए प्रकार में प्रतिनिधित्व करने योग्य नहीं है।
बेन वोइगट

1
@ लिह्यो: यह double x = 2/3;double y = 2.0/3;
बेन

5

खैर, पहली व्याख्या सही है। हालाँकि, इस संदर्भ में "हस्ताक्षरित शब्दार्थ" के बारे में आपका तर्क गलत है।

फिर, आपकी पहली व्याख्या सही है। बिना अंकगणित अंकगणित अंकगणित के नियमों का पालन करता है, जिसका अर्थ है कि 32-बिट अहस्ताक्षरित प्रकारों के लिए 0x0000 - 0x0001मूल्यांकन करता है 0xFFFF

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

उदाहरण के लिए, यह मूल्यांकन

signed int a = 0, b = 1;
unsigned int c = a - b;

अभी भी निर्माण करने के लिए गारंटी है UINT_MAXमें c, भले ही मंच पर हस्ताक्षर किए पूर्णांक के लिए एक विदेशी प्रतिनिधित्व उपयोग कर रहा है।


4
मुझे लगता है कि आपका मतलब 16 बिट अहस्ताक्षरित प्रकार है, न कि 32 बिट।
xioxox

4

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

ध्यान दें कि इससे कम संख्या वाले अहस्ताक्षरित को घटाव से पहले unsigned intटाइप करने के लिए प्रचारित किया जा सकता है int, का व्यवहार a-bआकार पर निर्भर करेगा int

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