operators entry बिटवाई शिफ्ट(बिट-शिफ्ट) ऑपरेटर क्या हैं और वे कैसे काम करते हैं?




डोमेस्टिक डाटा एंट्री ऑपरेटर क्या है (7)

मैं अपने खाली समय में सी सीखने का प्रयास कर रहा हूं, और अन्य भाषाओं (सी #, जावा, इत्यादि) में एक ही अवधारणा है (और अक्सर एक ही ऑपरेटर) ...

मैं क्या सोच रहा हूं, कोर स्तर पर, बिट-स्थानांतरण (<<, >>, >>>) क्या करता है, यह किस समस्या को हल करने में मदद कर सकता है, और मोड़ के चारों ओर क्या मिल रहा है? दूसरे शब्दों में, एक पूर्ण शुरुआत करने वाला गाइड अपनी सभी भलाई में थोड़ा सा स्थानांतरित करने के लिए।


बिटकवे ऑपरेशंस, बिट शिफ्ट समेत, निम्न स्तर के हार्डवेयर या एम्बेडेड प्रोग्रामिंग के लिए मूलभूत हैं। यदि आप किसी डिवाइस या यहां तक ​​कि कुछ बाइनरी फ़ाइल स्वरूपों के लिए एक विनिर्देश पढ़ते हैं, तो आपको बाइट्स, शब्द और डिक्शनरी दिखाई देंगे, जो गैर-बाइट गठबंधन बिटफील्ड में विभाजित हैं, जिनमें रुचि के विभिन्न मूल्य शामिल हैं। पढ़ने / लिखने के लिए इन बिट-फ़ील्ड तक पहुंच सबसे आम उपयोग है।

ग्राफिक्स प्रोग्रामिंग में एक साधारण वास्तविक उदाहरण यह है कि 16-बिट पिक्सेल निम्नानुसार दर्शाया गया है:

  bit | 15| 14| 13| 12| 11| 10| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1  | 0 |
      |       Blue        |         Green         |       Red          |

हरे रंग के मूल्य पर पहुंचने के लिए आप यह करेंगे:

 #define GREEN_MASK  0x7E0
 #define GREEN_OFFSET  5

 // Read green
 uint16_t green = (pixel & GREEN_MASK) >> GREEN_OFFSET;

व्याख्या

केवल हरे रंग के मूल्य को प्राप्त करने के लिए, जो ऑफसेट 5 से शुरू होता है और 10 (यानी 6-बिट लंबा) पर समाप्त होता है, आपको एक (बिट) मास्क का उपयोग करने की आवश्यकता होती है, जो पूरे 16-बिट पिक्सेल के खिलाफ लागू होने पर, उपज करेगी केवल उन बिट्स जिनमें हम रुचि रखते हैं।

#define GREEN_MASK  0x7E0

उचित मुखौटा 0x7E0 है जो बाइनरी में 0000011111100000 (जो दशमलव में 2016 है)।

uint16_t green = (pixel & GREEN_MASK) ...;

मास्क लागू करने के लिए, आप एंड ऑपरेटर (&) का उपयोग करते हैं।

uint16_t green = (pixel & GREEN_MASK) >> GREEN_OFFSET;

मुखौटा लगाने के बाद, आप 16-बिट संख्या के साथ समाप्त हो जाएंगे जो वास्तव में केवल 11-बिट संख्या है क्योंकि इसकी एमएसबी 11 वीं बिट में है। हरा वास्तव में केवल 6-बिट लंबा होता है, इसलिए हमें इसे सही शिफ्ट (11 - 6 = 5) का उपयोग करके स्केल करने की आवश्यकता होती है, इसलिए ऑफसेट के रूप में 5 का उपयोग ( #define GREEN_OFFSET 5 )।

फास्ट गुणा और विभाजन की शक्तियों के द्वारा बिट शिफ्ट का उपयोग करना भी सामान्य है 2:

 i <<= x;  // i *= 2^x;
 i >>= y;  // i /= 2^y;

एक गोचा यह है कि निम्नलिखित कार्यान्वयन निर्भर है (एएनएसआई मानक के अनुसार):

char x = -1;
x >> 1;

एक्स अब 127 (01111111) या अभी भी -1 (11111111) हो सकता है।

अभ्यास में, यह आमतौर पर उत्तरार्द्ध है।


ध्यान दें कि जावा कार्यान्वयन में, बिट्स की संख्या को स्थानांतरित करने के लिए स्रोत के आकार से संशोधित किया जाता है।

उदाहरण के लिए:

(long) 4 >> 65

बराबर 2. आप उम्मीद कर सकते हैं कि बिट्स को सही तरीके से 65 गुना स्थानांतरित करने की उम्मीद हो सकती है, लेकिन यह वास्तव में बराबर है:

(long) 4 >> (65 % 64)

यह <<, >>, और >>> के लिए सच है। मैंने इसे अन्य भाषाओं में नहीं देखा है।


इस बारे में जागरूक रहें कि विंडोज प्लेटफ़ॉर्म पर PHP का केवल 32 बिट संस्करण उपलब्ध है।

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

बेशक यदि आप PHP (यूनिक्स) के 64 बिट संस्करण का उपयोग करते हैं, तो आपको 63 बिट्स से अधिक स्थानांतरित होने से बचना चाहिए। हालांकि, उदाहरण के लिए, MySQL 64-बिट बिगिनट का उपयोग करता है, इसलिए कोई संगतता समस्या नहीं होनी चाहिए।

अद्यतन: PHP7 विंडोज़ से, php builds अंततः पूर्ण 64 बिट पूर्णांक का उपयोग करने में सक्षम हैं: पूर्णांक का आकार प्लेटफ़ॉर्म-निर्भर है, हालांकि अधिकतम दो बिल का अधिकतम मूल्य सामान्य मान है (यह 32 बिट्स हस्ताक्षरित है)। 64-बिट प्लेटफार्मों में आमतौर पर लगभग 9ई 18 का अधिकतम मूल्य होता है, विंडोज 7 को विंडोज़ से पहले छोड़कर, जहां यह हमेशा 32 बिट था।


बिट स्थानांतरण ऑपरेटरों वास्तव में उनके नाम का तात्पर्य करते हैं। वे बिट्स को स्थानांतरित करते हैं। विभिन्न शिफ्ट ऑपरेटरों के लिए यहां एक संक्षिप्त (या संक्षिप्त नहीं) परिचय दिया गया है।

ऑपरेटर

  • >> अंकगणित (या हस्ताक्षरित) सही शिफ्ट ऑपरेटर है।
  • >>> तार्किक (या हस्ताक्षरित) सही शिफ्ट ऑपरेटर है।
  • << बाएं शिफ्ट ऑपरेटर है, और दोनों तार्किक और अंकगणितीय बदलावों की आवश्यकताओं को पूरा करता है।

इन सभी ऑपरेटरों को पूर्णांक मानों ( int , long , संभवतः short और byte या char ) पर लागू किया जा सकता है। कुछ भाषाओं में, शिफ्ट ऑपरेटरों को int से कम किसी भी डेटाटाइप पर लागू करने से स्वचालित रूप से ऑपरेंड का आकार बदल जाता है।

ध्यान दें कि <<< एक ऑपरेटर नहीं है, क्योंकि यह अनावश्यक होगा। यह भी ध्यान रखें कि सी और सी ++ सही शिफ्ट ऑपरेटरों के बीच अंतर नहीं करते हैं। वे केवल >> ऑपरेटर प्रदान करते हैं, और दाएं-स्थानांतरण व्यवहार को हस्ताक्षरित प्रकारों के लिए परिभाषित किया गया है।

बाएं शिफ्ट (<<)

बिट्स की श्रृंखला के रूप में, स्मृति में, इंटीजर संग्रहीत होते हैं। उदाहरण के लिए, 32-बिट int रूप में संग्रहीत नंबर 6 होगा:

00000000 00000000 00000000 00000110

इस बिट पैटर्न को बाएं एक स्थिति में स्थानांतरित करना ( 6 << 1 ) परिणामस्वरूप संख्या 12:

00000000 00000000 00000000 00001100

जैसा कि आप देख सकते हैं, अंक बाईं ओर एक स्थान से स्थानांतरित हो गए हैं, और दाईं ओर अंतिम अंक शून्य से भरा हुआ है। आप यह भी ध्यान दे सकते हैं कि बाएं स्थानांतरित करना 2 की शक्तियों के गुणा के बराबर है। इसलिए 6 << 1 6 * 2 बराबर है, और 6 << 3 6 * 8 बराबर है। एक अच्छा अनुकूलन संकलक जब संभव हो तो बदलावों के साथ गुणाओं को प्रतिस्थापित करेगा।

गैर परिपत्र स्थानांतरण

कृपया ध्यान दें कि ये गोलाकार बदलाव नहीं हैं। इस मान को बाईं ओर एक स्थान पर स्थानांतरित करना ( 3,758,096,384 << 1 ):

11100000 00000000 00000000 00000000

परिणाम 3,221,225,472:

11000000 00000000 00000000 00000000

वह अंक जो "अंत से बाहर" स्थानांतरित हो जाता है, खो जाता है। यह चारों ओर लपेट नहीं है।

तार्किक सही शिफ्ट (>>>)

एक तार्किक दायां शिफ्ट बाएं शिफ्ट के विपरीत है। बाईं ओर बिट्स को स्थानांतरित करने के बजाय, वे बस दाईं ओर जाते हैं। उदाहरण के लिए, संख्या 12 स्थानांतरित करना:

00000000 00000000 00000000 00001100

एक स्थिति से दाएं ( 12 >>> 1 ) हमारे मूल 6 वापस आ जाएगा:

00000000 00000000 00000000 00000110

तो हम देखते हैं कि दाईं ओर स्थानांतरित करना 2 की शक्तियों के विभाजन के बराबर है।

खोया बिट्स चले गए हैं

हालांकि, एक बदलाव "खो" बिट्स को पुनः प्राप्त नहीं कर सकता है। उदाहरण के लिए, यदि हम इस पैटर्न को बदलते हैं:

00111000 00000000 00000000 00000110

बाएं 4 पदों पर ( 939,524,102 << 4 9, 939,524,102 << 4 ), हमें 2,147,483,744 मिलते हैं:

10000000 00000000 00000000 01100000

और फिर वापस स्थानांतरित ( (939,524,102 << 4) >>> 4 ) हमें 134,217,734 मिलते हैं:

00001000 00000000 00000000 00000110

एक बार जब हम बिट्स खो देते हैं तो हम अपने मूल मूल्य को वापस नहीं प्राप्त कर सकते हैं।

अंकगणित सही शिफ्ट (>>)

अंकगणितीय दायां शिफ्ट शून्य के साथ पैडिंग के बजाय, तार्किक दाएं शिफ्ट की तरह है, यह सबसे महत्वपूर्ण बिट के साथ पैड है। ऐसा इसलिए है क्योंकि सबसे महत्वपूर्ण बिट साइन बिट है, या बिट जो सकारात्मक और नकारात्मक संख्याओं को अलग करता है। सबसे महत्वपूर्ण बिट के साथ पैडिंग करके, अंकगणित सही शिफ्ट साइन-संरक्षित है।

उदाहरण के लिए, यदि हम इस बिट पैटर्न को ऋणात्मक संख्या के रूप में समझते हैं:

10000000 00000000 00000000 01100000

हमारे पास संख्या -2,147,483,552 है। अंकगणितीय शिफ्ट (-2,147,483,552 >> 4) के साथ इसे सही 4 पदों पर स्थानांतरित करने से हमें यह मिल जाएगा:

11111000 00000000 00000000 00000110

या संख्या -134,217,722।

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


बिट मास्किंग और स्थानांतरण

बिट स्थानांतरण को अक्सर निम्न स्तर के ग्राफिक्स प्रोग्रामिंग में उपयोग किया जाता है। उदाहरण के लिए 32-बिट शब्द में एन्कोड किए गए दिए गए पिक्सेल रंग मान।

 Pixel-Color Value in Hex:    B9B9B900
 Pixel-Color Value in Binary: 10111001  10111001  10111001  00000000

बेहतर समझने के लिए, वही द्विआधारी मूल्य लेबल करता है जो अनुभागों का प्रतिनिधित्व करता है जो रंग भाग का प्रतिनिधित्व करता है।

                                 Red     Green     Blue       Alpha
 Pixel-Color Value in Binary: 10111001  10111001  10111001  00000000

आइए उदाहरण के लिए हम इस पिक्सल रंग का हरा मान प्राप्त करना चाहते हैं। हम मास्किंग और स्थानांतरण द्वारा आसानी से उस मूल्य को प्राप्त कर सकते हैं।

हमारा मुखौटा:

                  Red      Green      Blue      Alpha
 color :        10111001  10111001  10111001  00000000
 green_mask  :  00000000  11111111  00000000  00000000

 masked_color = color & green_mask

 masked_color:  00000000  10111001  00000000  00000000

तार्किक & ऑपरेटर यह सुनिश्चित करता है कि केवल वे मान जहां मास्क 1 रखा जाता है। आखिरी चीज जो हमें अब करना है, वह उन सभी बिट्स को 16 स्थानों (तार्किक दाएं शिफ्ट) से दाएं स्थानांतरित करके सही पूर्णांक मान प्राप्त करना है।

 green_value = masked_color >>> 16

और voilá, हमारे पास पिक्सल रंग में हरे रंग की मात्रा का प्रतिनिधित्व करने वाला पूर्णांक है:

 Pixels-Green Value in Hex:     000000B9
 Pixels-Green Value in Binary:  00000000 00000000 00000000 10111001 
 Pixels-Green Value in Decimal: 185

यह अक्सर एन्कोडिंग या डीकोडिंग छवि प्रारूपों जैसे jpg , png , ... लिए प्रयोग किया जाता है।


मैं केवल युक्तियाँ और चाल लिख रहा हूं, परीक्षण / परीक्षाओं में उपयोगी पा सकता हूं।

  1. n = n*2 : n = n<<1
  2. n = n/2 : n = n>>1
  3. जांच रहा है कि एन 2 की शक्ति है (1,2,4,8, ...): जांचें !(n & (n-1))
  4. X का x वें प्राप्त करना n : n |= (1 << x)




binary-operators