2010-08-25 7 views
9

EDIT सार्वजनिक स्वास्थ्य चेतावनी - इस प्रश्न में अपरिभाषित व्यवहार के बारे में झूठी धारणा शामिल है। स्वीकृत उत्तर देखें।कोई अपरिभाषित व्यवहार के साथ डबल-चंक जोड़ने के लिए कैसे करें?

recent blog post पढ़ने के बाद, मैं सी और सी ++ कोड में सभी मानकों-अपरिभाषित धारणाओं से बचने की व्यावहारिकता के बारे में बहुत कुछ सोच रहा हूं। यहाँ एक टुकड़ा सी ++ से बाहर काट, एक अहस्ताक्षरित 128 बिट इसके अलावा करने के लिए ...

void c_UInt64_Pair::operator+= (const c_UInt64_Pair &p) 
{ 
    m_Low += p.m_Low; 
    m_High += p.m_High; 

    if (m_Low < p.m_Low) m_High++; 
} 

यह स्पष्ट रूप से अतिप्रवाह व्यवहार के बारे में मान्यताओं पर निर्भर करता है। जाहिर है कि ज्यादातर मशीन सही प्रकार के बाइनरी पूर्णांक का समर्थन कर सकती हैं (हालांकि शायद 32-बिट भाग या जो कुछ भी हो), लेकिन स्पष्ट रूप से एक बढ़ता मौका है कि ऑप्टिमाइज़र मानकों को अपरिभाषित व्यवहार कर सकता है। यही कारण है कि m_Low < p.m_Low स्थिति पास हो सकती है यदि m_Low += p.m_Low अतिप्रवाह, जो अपरिभाषित व्यवहार है, इसलिए ऑप्टिमाइज़र कानूनी रूप से निर्णय ले सकता है कि हमेशा विफल रहता है। इस मामले में, यह कोड बस टूटा हुआ है।

सवाल है, इसलिए ...

कैसे आप ऊपर के एक यथोचित कुशल संस्करण अपरिभाषित व्यवहार पर निर्भर रहे बिना लिख ​​सकते है?

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

संपादित नाबालिग स्पष्टीकरण - यह सिर्फ अतिप्रवाह का पता लगाने, लेकिन यह भी सुनिश्चित करना है कि दोनों m_Low और m_High सही सापेक्ष साथ खत्म 2^64 परिणाम है, जो भी मानकों पर अपरिभाषित है के बारे में नहीं है।

+3

1/यह सी नहीं है। आप इस सवाल को "सी" क्यों टैग करते हैं? 2/यदि यह सी थे, और शायद सी ++ में भी, यह अपरिभाषित व्यवहार पर भरोसा नहीं करेगा: हस्ताक्षरित अभिन्न प्रकार ओवरफ़्लो परिभाषित किए गए हैं और मॉड्यूलो व्यवहार है: C99 मानक में 6.2.5.9। –

+0

@ पास्कल: दरअसल, धारा 5 देखें।सबसे हालिया मसौदे में से 4 (मेरे पास सी ++ 03 मानक नहीं है, लेकिन मेरा मानना ​​है कि व्यवहार नहीं बदला है) - "यदि अभिव्यक्ति के मूल्यांकन के दौरान, परिणाम गणितीय रूप से परिभाषित नहीं किया गया है या नहीं इसके प्रकार के लिए प्रतिनिधित्व योग्य मूल्यों की सीमा, व्यवहार अपरिभाषित है। " –

+2

@ पास्कल - (1) प्रश्न सी और सी ++ के समान है। केवल एक में एक उदाहरण प्रदान करना इसका मतलब यह नहीं है कि प्रश्न केवल उस के बारे में है। (2) ऐसा कब हुआ? यदि यह सच है तो यह उत्तर है (सी ++ ने अभी तक प्रासंगिक सी नियम आयात नहीं किया हो सकता है, लेकिन यदि नहीं, तो इसमें कोई संदेह नहीं होगा), इसलिए इसे संदर्भ के साथ उत्तर में रखें और मैं स्वीकार करूंगा। – Steve314

उत्तर

14

सी ++ 1998 मानक से 3.9.1 (4): "बिना हस्ताक्षरित पूर्णांक, हस्ताक्षरित घोषित, अंकगणित मॉड्यूलो 2^एन के नियमों का पालन करेंगे जहां एन उस विशेष आकार के मूल्य प्रतिनिधित्व में बिट्स की संख्या है पूर्णांक। " ध्यान दें कि "पूर्णांक", यहां int की बजाय किसी भी पूर्णांक प्रकार को संदर्भित करता है।

इसलिए, यह मानते हुए कि वे हस्ताक्षर किए गए पूर्णांक हैं, जैसे कि "UInt64" प्रकार बताता है, यह सी ++ में परिभाषित व्यवहार है और उम्मीद के अनुसार काम करना चाहिए।

+0

सी ++ 1995 मानक क्या है? मुझे '99, '03 के बारे में पता है ... कभी भी इसके बारे में नहीं सुना। किसी भी मामले में, जबकि यह सच है, इसका मतलब यह नहीं है कि अतिप्रवाह व्यवहार परिभाषित किया गया है , मैंने ऊपर उद्धृत अनुभाग देखें - "यदि अभिव्यक्ति के मूल्यांकन के दौरान, परिणाम गणितीय रूप से परिभाषित नहीं है या इसके प्रकार के लिए प्रतिनिधित्व योग्य मानों की सीमा में नहीं है, तो व्यवहार अपरिभाषित है।" –

+4

@ बिली, क्योंकि हस्ताक्षरित प्रकारों का पालन करें मॉड्यूलो अंकगणितीय के नियम, कभी भी परिणाम नहीं होंगे जो प्रतिनिधित्व मूल्यों की सीमा से बाहर है, इसलिए व्यवहार परिभाषित किया गया है। 3.9.1/4 पर फुटनोट उतना ही कहता है। –

+0

@ रोब: आह .. फुटनोट करता है स्पष्ट करें कि। मैं इस बात का विरोध करता हूं कि वह जिस मार्ग का उल्लेख करता है वह वह मूल रूप से स्पष्ट नहीं करता है। –

0

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

असल में, प्रत्येक 64-बिट घटक के लिए, आपको कम 63 बिट्स और उच्चतम बिट्स का उपयोग करके जोड़ों की अलग-अलग गणना करने की आवश्यकता है। इन अलग-अलग गणनाओं से आप काम कर सकते हैं कि 64-बिट कुल क्या था, और यदि कोई वाहक था।

फिर जब आप ऊपरी 64-बिट जोड़ करते हैं, तो आप वाहक में जोड़ते हैं, यदि कोई है तो। यदि उस से कोई कैर्री परिणाम होता है, तो आपने अपना 128-बिट वैरिएबल ओवरफ़्लो कर दिया है, और आपको अपवाद ट्रिगर करने की आवश्यकता होगी, या अन्यथा केस को संभालना होगा।

+4

नहीं; जो आप कहते हैं वह हस्ताक्षरित अभिन्न प्रकारों के लिए सच है, लेकिन हस्ताक्षरित नहीं है। –

+0

आन्द ... आप सी या सी ++ में कुशलतापूर्वक ऐसा क्यों नहीं कर पाएंगे? आप कौन सा विकल्प सुझाएंगे * अधिक * कुशल होगा? –

+1

सबसे अधिक कुशलतापूर्वक वास्तव में इस उद्देश्य के लिए प्रदान की गई हार्डवेयर सुविधाओं का उपयोग करना होगा, चाहे 128-बिट रजिस्ट्रार हों या झंडे रखें। – swestrup