कुछ दिन पहले, StackExchange सदस्य Anto ने बिट-वार ऑपरेटरों के लिए वैध उपयोगों के बारे में पूछताछ की । मैंने कहा कि दो की शक्तियों द्वारा पूर्णांकों को गुणा और विभाजित करने की तुलना में शिफ्टिंग तेज थी। StackExchange सदस्य डेमिन ने बताया कि राइट-शिफ्टिंग ने नकारात्मक संख्याओं के साथ समस्याओं को प्रस्तुत किया।
उस बिंदु पर, मैंने कभी भी हस्ताक्षरित पूर्णांक के साथ शिफ्ट ऑपरेटरों का उपयोग करने के बारे में नहीं सोचा था। मैंने मुख्य रूप से निम्न-स्तरीय सॉफ़्टवेयर विकास में इस तकनीक का उपयोग किया था; इसलिए, मैंने हमेशा अहस्ताक्षरित पूर्णांक का उपयोग किया। C अहस्ताक्षरित पूर्णांकों पर तार्किक बदलाव करता है। तार्किक शिफ्ट सही प्रदर्शन करते समय साइन बिट पर कोई ध्यान नहीं दिया जाता है। खाली बिट्स शून्य से भरे हुए हैं। हालाँकि, C एक अंकगणित शिफ्ट ऑपरेशन करता है जब एक हस्ताक्षरित पूर्णांक दाएं को स्थानांतरित करता है। खाली बिट्स साइन बिट से भरे हुए हैं। यह अंतर शून्य की ओर छंटनी होने के बजाय अनंत की ओर एक नकारात्मक मूल्य का कारण बनता है, जो हस्ताक्षरित पूर्णांक विभाजन की तुलना में एक अलग व्यवहार है।
कुछ मिनटों के विचार के परिणामस्वरूप पहले क्रम में समाधान हुआ। समाधान सशर्त रूप से नकारात्मक मूल्यों को स्थानांतरित करने से पहले सकारात्मक मूल्यों में परिवर्तित करता है। शिफ्ट ऑपरेशन किए जाने के बाद एक मान सशर्त रूप से अपने नकारात्मक रूप में परिवर्तित हो जाता है।
int a = -5;
int n = 1;
int negative = q < 0;
a = negative ? -a : a;
a >>= n;
a = negative ? -a : a;
इस समाधान के साथ समस्या यह है कि सशर्त असाइनमेंट स्टेटमेंट्स का आमतौर पर कम से कम एक जंप इंस्ट्रक्शन में अनुवाद किया जाता है, और जंप निर्देश प्रोसेसर पर महंगे हो सकते हैं जो दोनों इंस्ट्रक्शन पाथ को डिकोड नहीं करते हैं। डिवाइडर के ऊपर शिफ्ट करने से प्राप्त किसी भी प्रदर्शन लाभ में एक निर्देश पाइपलाइन को दो बार फिर से प्रधान करना एक अच्छा सेंध बनाता है।
उपर्युक्त के साथ, मैं शनिवार को सशर्त असाइनमेंट समस्या के उत्तर के साथ जाग गया। एक अंकगणितीय पारी ऑपरेशन करते समय हमें जो समस्या आती है वह केवल दो पूरक प्रतिनिधित्व के साथ काम करते समय होती है। यह किसी के पूरक प्रतिनिधित्व के साथ नहीं होता है। समस्या के समाधान में शिफ्ट ऑपरेशन करने से पहले किसी के पूरक मूल्य में दो के पूरक मूल्य को परिवर्तित करना शामिल है। हमें फिर किसी के पूरक मूल्य को दो के पूरक मूल्य में बदलना होगा। हैरानी की बात यह है कि हम बदलाव ऑपरेशन को करने से पहले नकारात्मक मूल्यों को सशर्त रूप से परिवर्तित किए बिना संचालन के इस सेट को निष्पादित कर सकते हैं।
int a = -5;
int n = 1;
register int sign = (a >> INT_SIZE_MINUS_1) & 1
a = (a - sign) >> n + sign;
एक दो के पूरक नकारात्मक मूल्य एक को घटाकर एक नकारात्मक पूरक के मूल्य में परिवर्तित हो जाते हैं। दूसरी तरफ, किसी के पूरक ऋणात्मक मान को एक में जोड़कर नकारात्मक पूरक के दो पूरक में बदल दिया जाता है। ऊपर सूचीबद्ध कोड काम करता है क्योंकि साइन बिट का उपयोग दो के पूरक से किसी के पूरक में बदलने के लिए किया जाता है और इसके विपरीत । केवल नकारात्मक मानों में उनके साइन बिट सेट होंगे; इसलिए, चर संकेत शून्य के बराबर होगा जब एक सकारात्मक है।
उपर्युक्त के साथ, क्या आप अन्य बिट-वार हैक के बारे में सोच सकते हैं जैसे कि ऊपर वाले ने इसे आपके चाल की थैली में बनाया है? आपकी पसंदीदा बिट-वार हैक क्या है? मैं हमेशा नए प्रदर्शन-उन्मुख बिट-वार हैक की तलाश में हूं।