2009-10-20 6 views
18

सी/सी ++ मानक (see this link) के अनुसार, सी और सी ++ में >> ऑपरेटर हस्ताक्षरित संख्याओं के लिए एक अंकगणितीय बदलाव नहीं है। यह कंपाइलर कार्यान्वयन पर निर्भर करता है कि 0 (लॉजिकल) या साइन बिट (अंकगणितीय) को स्थानांतरित किया गया है क्योंकि बिट्स को दाईं ओर स्थानांतरित किया गया है।सत्यापित करना कि सी/सी ++ सही शिफ्ट पर हस्ताक्षर किए गए एक विशेष संकलक के लिए अंकगणित है?

क्या यह कोड हस्ताक्षर किए गए पूर्णांक के लिए लॉजिकल राइट शिफ्ट लागू करने वाले कंपाइलर्स के लिए संकलन समय पर एएसएसईआरटी (असफल) पर कार्य करेगा?

#define COMPILE_TIME_ASSERT(EXP) \ 
    typedef int CompileTimeAssertType##__LINE__[(EXP) ? 1 : -1] 

#define RIGHT_SHIFT_IS_ARITHMETIC \ 
    ((((signed int)-1)>>1) == ((signed int)-1)) 

// SHR must be arithmetic to use this code 
COMPILE_TIME_ASSERT(RIGHT_SHIFT_IS_ARITHMETIC); 
+3

उन लोगों के लिए आपके असफल संकलन क्या हैं जिनके पास एक तार्किक बदलाव का उपयोग करने वाली मशीन है? ऐसा सॉफ़्टवेयर ऐसी मशीन/कंपाइलर पर उपयोग करने योग्य क्यों नहीं है? क्या कोड लिखना बेहतर नहीं होगा, इस पर ध्यान दिए बिना कि हस्ताक्षरित संख्या की सही शिफ्ट अंकगणित या तार्किक है या नहीं? –

+6

मैं बिट ट्विडलिंग के माध्यम से शाखा-मुक्त चयन (बीएफएस) का उपयोग कर रहा हूं। इसे काम करने के लिए एक अंकगणितीय बदलाव की आवश्यकता है। मैं COMPILE_TIME_ASSERT (RIGHT_SHIFT_IS_ARITHMETIC) डाल रहा हूं; बीएफएस हेडर में। कोड को पारंपरिक या शाखा-मुक्त पथ चुनने के लिए RIGHT_SHIFT_IS_ARITHMETIC परिभाषित करने की आवश्यकता है। शाखा गलत तरीके से दंड के कारण यह शाखा-मुक्त कोड का उपयोग करने के लिए पीएस 3/एक्सबॉक्स 360 सीपीयू पर भारी गति से हो सकता है। – Adisak

+1

बीटीडब्लू, संकलन समय पर असफल संकलन जहां स्पष्ट रूप से उल्लेख किया गया है, कोड को रहस्यमय रूप से असफल होने से बेहतर है ... मूल रूप से यह कहने जा रहा है कि ये दिनचर्या इस कंपाइलर (या सीपीयू) द्वारा समर्थित नहीं हैं। – Adisak

उत्तर

6

मेरे लिए अच्छा लग रहा है! आप एक असेंबली फ़ाइल को निकालने के लिए कंपाइलर भी सेट कर सकते हैं (या डीबगर में संकलित प्रोग्राम लोड कर सकते हैं) और signed int i; i >> 1; के लिए कौन सा ऑपोड उत्सर्जित करता है, लेकिन यह आपके समाधान की तरह स्वचालित नहीं है।

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

+0

हाँ, मैं मूल रूप से इसे स्वचालित करना चाहते हैं ... opcodes को देखकर इस आवश्यकता के लिए उचित उम्मीद नहीं है क्योंकि मैं इसे पुस्तकालय में उपयोग कर रहा हूं कि अन्य टीम विभिन्न प्लेटफ़ॉर्म पर उपयोग कर सकती हैं। – Adisak

+0

[UNISYS 2200 सिस्टम] के लिए संकलक (http://stackoverflow.com/a/12277974/995714) हस्ताक्षरित प्रकारों के लिए तार्किक दायां शिफ्ट का उपयोग करता है। "अभिव्यक्ति ई 1 >> ई 2 का परिणाम यह है कि ई 1 (थोड़ा पैटर्न के रूप में व्याख्या किया गया है) को सही ई 2 बिट पोजिशन में स्थानांतरित किया गया है। सही शिफ्ट * तार्किक है (यानी, बाईं ओर शून्य-भरी हुई) भले ही ई 1 अभिव्यक्ति एक हस्ताक्षरित पूर्णांक प्रकार * है। " http://public.support.unisys.com/2200/docs/cp14.0/pdf/78310422-011.pdf –

1

क्यों जोर देते हैं? यदि आपके कंपाइलर का शिफ्ट ऑपरेटर आपकी आवश्यकताओं के अनुरूप नहीं है, तो आप परिणाम को साइन-अप करके स्थिति का सावधानीपूर्वक उपाय कर सकते हैं। इसके अलावा, कभी-कभी रन-टाइम काफी अच्छा होता है। सब के बाद, संकलक के अनुकूलक चलाने के समय से बाहर संकलन समय कर सकते हैं:

template <typename Number> 
inline Number shift_logical_right(Number value, size_t bits) 
{ 
    static const bool shift_is_arithmetic = (Number(-1) >> 1) == Number(-1); 
    const bool negative = value < 0; 
    value >>= bits; 
    if (!shift_is_arithmetic && negative) // sign extend 
     value |= -(Number(1) << (sizeof(Number) * 8 - bits)); 
} 

static const bool, संकलन समय पर मूल्यांकन किया जा सकता है, इसलिए यदि shift_is_arithmetictrue होने की गारंटी है, लायक हर संकलक उसके नमक को समाप्त होगा पूरे if खंड और const bool negative का निर्माण मृत कोड के रूप में।

नोट: कोड मोनो के encode_sleb128 फ़ंक्शन से अनुकूलित किया गया है: here

अद्यतन

तुम सच में अंकगणित पारी बिना मशीनों पर संकलन निरस्त करना चाहते हैं, तो आप अभी भी पूर्वप्रक्रमक पर भरोसा नहीं से बेहतर कर रहे हैं। आप static_assert (या BOOST_STATIC_ASSERT) का उपयोग कर सकते हैं:

static_assert((Number(-1) >> 1) == Number(-1), "Arithmetic shift unsupported."); 
+0

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

+0

पर्याप्त मेला। फिर भी, मेरा दूसरा बिंदु अभी भी वैध है: प्रीप्रोसेसर पर भरोसा न करें। अद्यतन देखें। – marton78

+1

static_assert() सी ++ 11x है और हम बूस्ट का उपयोग नहीं कर सकते हैं। लेकिन मैं जो चेक कर रहा था वह प्रीप्रोसेसर पर भरोसा नहीं करता है, मैं बस निम्नलिखित कर सकता हूं लेकिन मैंने जो उदाहरण लिखा है उससे पढ़ने और समझना बहुत कठिन है: 'टाइपेडफ इंट कंपाइलटाइमएस्र्टअर्थेटाइटिक शिफ्ट [((((हस्ताक्षरित int) -1) >> 1) == ((हस्ताक्षरित int) -1))? 1: -1]; ' – Adisak

0

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

अलग-अलग व्यवहार का एक उदाहरण फ़्लोटिंग पॉइंट नंबरों के साथ पाया जा सकता है। क्या आपका कंपाइलर एकल, डबल, या विस्तारित परिशुद्धता में निरंतर अभिव्यक्ति गणित कर रहा है यदि आप int में वापस आ रहे हैं? जैसे

constexpr int a = 41; constexpr int बी = (ए/7.5);

मैं जो कह रहा हूं वह है, आपको यह सुनिश्चित करना चाहिए कि आपके कंपाइलर रन-टाइम के दौरान समान व्यवहार की गारंटी देते हैं जब आप कई अलग-अलग आर्किटेक्चर में काम कर रहे हों।

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

असेंबली आउटपुट देखने के लिए दुनिया का अंत नहीं है ... कितने अलग प्लेटफॉर्म हैं? चूंकि यह इतना प्रदर्शन-महत्वपूर्ण है, इसलिए 5 अलग-अलग आर्किटेक्चर के लिए असेंबलर आउटपुट की 1-3 लाइनों को देखने का "काम" करें।ऐसा नहीं है कि आपको अपनी लाइन ढूंढने के लिए एक संपूर्ण असेंबली आउटपुट (आमतौर पर!) के माध्यम से गोता लगाएँ। यह करना बहुत आसान है।

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