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


1380

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

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


2
जिन कार्यात्मक या गैर-कार्यात्मक मामलों में आप 3GL में बिटशिफ्टिंग का उपयोग करते हैं वे कुछ ही हैं।
ट्रॉय डेमनब्रून

14
इन उत्तरों को पढ़ने के बाद आप इन लिंक्स को देख सकते हैं: graphics.stanford.edu/~seander/bithacks.html & jjj.de/bitwizardry/bitwizardrypage.html
claws

1
यह ध्यान रखना महत्वपूर्ण है कि बिट-शिफ्टिंग कंप्यूटर के लिए बहुत आसान और तेज़ है। आप कार्यक्रम में बिट-शिफ्टिंग का उपयोग करने के तरीके खोजने से, आप मेमोरी उपयोग और निष्पादन समय को बहुत कम कर सकते हैं।
होयटमैन

@ हॉयटमैन: लेकिन ध्यान दें कि अच्छे कंपाइलर इनमें से कई ट्रिक्स पहले से जानते हैं और आमतौर पर यह पहचानने में बेहतर होते हैं कि यह कहां समझ में आता है।
सेबस्टियन मच

जवाबों:


1712

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

संचालक

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

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

ध्यान दें कि <<<एक ऑपरेटर नहीं है, क्योंकि यह निरर्थक होगा।

यह भी ध्यान दें कि C और C ++ सही शिफ्ट ऑपरेटरों के बीच अंतर नहीं करते हैं । वे केवल >>ऑपरेटर प्रदान करते हैं , और राइट-शिफ्टिंग व्यवहार कार्यान्वित प्रकारों के लिए परिभाषित किया गया है। शेष उत्तर C # / Java ऑपरेटरों का उपयोग करता है।

( >>हस्ताक्षरित प्रकारों पर जीसीसी और क्लैंग / एलएलवीएम सहित सभी मुख्य धारा सी और सी ++ कार्यान्वयन में अंकगणित है। कुछ कोड इसे मानते हैं, लेकिन यह मानक गारंटी नहीं है। यह अपरिभाषित नहीं है , हालांकि, मानक को इसे परिभाषित करने के लिए आवश्यक है। या दूसरी तरह से। हालांकि, नकारात्मक हस्ताक्षर किए संख्या के बाएँ बदलाव है अपरिभाषित व्यवहार (अतिप्रवाह पूर्णांक हस्ताक्षर किए)। तो जब तक आप गणित सही बदलाव की जरूरत है, यह आमतौर पर ऐसा करने के लिए एक अच्छा विचार है अपने बिट बदलने अहस्ताक्षरित प्रकार के साथ।)


वाम पारी (<<)

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

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), हमें 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 की शक्तियों द्वारा विभाजन का प्रदर्शन कर रहे हैं।


303
उत्तर को यह स्पष्ट करना चाहिए कि यह एक जावा-विशिष्ट उत्तर है। C / C ++ या C # में कोई >>> ऑपरेटर नहीं है, और क्या नहीं या नहीं> >> प्रचार का संकेत C / C ++ (एक प्रमुख संभावित गोच) में परिभाषित कार्यान्वयन है
माइकल बूर

55
सी भाषा के संदर्भ में उत्तर पूरी तरह से गलत है। सी में "अंकगणित" और "तार्किक" शिफ्ट में कोई सार्थक विभाजन नहीं है। सी में शिफ्ट अहस्ताक्षरित मूल्यों और सकारात्मक हस्ताक्षरित मूल्यों पर अपेक्षित रूप से काम करते हैं - वे बस बिट्स को स्थानांतरित करते हैं। नकारात्मक मूल्यों पर, राइट-शिफ्ट कार्यान्वयन को परिभाषित किया गया है (अर्थात सामान्य रूप से क्या होता है इसके बारे में कुछ भी नहीं कहा जा सकता है), और बाएं-शिफ्ट को बस निषिद्ध है - यह अपरिभाषित व्यवहार पैदा करता है।
चींटी

10
ऑड्रे, निश्चित रूप से अंकगणित और तार्किक सही स्थानांतरण के बीच अंतर है। सी बस परिभाषित कार्यान्वयन को छोड़ देता है। और नकारात्मक मूल्यों पर बाईं पारी निश्चित रूप से निषिद्ध नहीं है। 0xff000000 को बाईं ओर शिफ्ट करें और आपको 0xfe000000 मिलेगा।
डेरेक पार्क

16
A good optimizing compiler will substitute shifts for multiplications when possible. क्या? Bitshifts परिमाण के आदेश तेजी से जब यह एक सीपीयू के निम्न स्तर के संचालन के लिए नीचे आता है कर रहे हैं, एक अच्छा संकलक का अनुकूलन करना होगा सटीक विपरीत, वह है, थोड़ा बदलाव में दो की शक्तियों द्वारा साधारण गुणा मोड़।
महन

55
@ मेन, आप इसे मेरे इरादे से पीछे की ओर पढ़ रहे हैं। X के लिए स्थानापन्न Y का अर्थ है X को Y के साथ बदलना। Y, X का स्थानापन्न है। इसलिए बदलाव गुणन का विकल्प है।
डेरेक पार्क

208

मान लीजिए कि हमारे पास एक ही बाइट है:

0110110

सिंगल लेफ्ट बिटशिफ्ट लगाने से हमें मिलता है:

1101100

बाईं ओर के शून्य को बाइट से स्थानांतरित कर दिया गया था, और बाइट के दाईं ओर एक नया शून्य जोड़ा गया था।

बिट्स रोलओवर नहीं करते हैं; उन्हें छोड़ दिया जाता है। इसका मतलब है कि यदि आपने 1101100 की शिफ्ट छोड़ दी है और फिर इसे राइट शिफ्ट कर दिया है, तो आपको वही परिणाम वापस नहीं मिलेगा।

N द्वारा छोड़ा गया शिफ्टिंग 2 N से गुणा करने के बराबर है ।

N द्वारा शिफ्टिंग सही है (यदि आप लोगों के पूरक का उपयोग कर रहे हैं ) 2 N से विभाजित होने और शून्य पर गोलाई के बराबर है।

बिटशफ्टिंग का उपयोग बहुत तेजी से गुणा और भाग के लिए किया जा सकता है, बशर्ते आप 2 की शक्ति के साथ काम कर रहे हों। लगभग सभी निम्न-स्तरीय ग्राफिक्स रूटीन बिटशफ्टिंग का उपयोग करते हैं।

उदाहरण के लिए, पुराने दिनों में वापस, हमने खेलों के लिए मोड 13h (320x200 256 रंग) का उपयोग किया। मोड 13 एच में, वीडियो मेमोरी को प्रति पिक्सेल क्रमिक रूप से निर्धारित किया गया था। इसका मतलब एक पिक्सेल के लिए स्थान की गणना करना है, आप निम्नलिखित गणित का उपयोग करेंगे:

memoryOffset = (row * 320) + column

अब, उस दिन और उम्र में, गति महत्वपूर्ण थी, इसलिए हम इस ऑपरेशन को करने के लिए बिटशिफ्ट्स का उपयोग करेंगे।

हालाँकि, 320 दो की शक्ति नहीं है, इसलिए इसके चारों ओर जाने के लिए हमें यह पता लगाना होगा कि दो में से कौन सी एक शक्ति है जो एक साथ जुड़कर 320 बनाता है:

(row * 320) = (row * 256) + (row * 64)

अब हम इसे बाईं ओर बदल सकते हैं:

(row * 320) = (row << 8) + (row << 6)

अंतिम परिणाम के लिए:

memoryOffset = ((row << 8) + (row << 6)) + column

अब हमें पहले की तरह ही ऑफ़सेट मिलता है, महंगे गुणा-भाग के ऑपरेशन को छोड़कर, हम दो बिटशिफ्ट्स का उपयोग करते हैं ... x86 में यह कुछ इस तरह होगा (ध्यान दें, यह हमेशा से रहा है जब से मैंने असेंबली की है) (संपादक का नोट: सही किया कुछ गलतियाँ और एक 32-बिट उदाहरण जोड़ा)):

mov ax, 320; 2 cycles
mul word [row]; 22 CPU Cycles
mov di,ax; 2 cycles
add di, [column]; 2 cycles
; di = [row]*320 + [column]

; 16-bit addressing mode limitations:
; [di] is a valid addressing mode, but [ax] isn't, otherwise we could skip the last mov

कुल: 28 सीपीयू जो भी प्राचीन सीपीयू में ये समय था।

वीआरएस

mov ax, [row]; 2 cycles
mov di, ax; 2
shl ax, 6;  2
shl di, 8;  2
add di, ax; 2    (320 = 256+64)
add di, [column]; 2
; di = [row]*(256+64) + [column]

एक ही प्राचीन सीपीयू पर 12 चक्र।

हां, हम 16 सीपीयू साइकिलों को शेव करने के लिए यह मेहनत करेंगे।

32 या 64-बिट मोड में, दोनों संस्करण बहुत छोटे और तेज हो जाते हैं। इंटेल स्काईलेक (देखें http://agner.org/optimize/ ) जैसे आधुनिक आउट-ऑफ-ऑर्डर निष्पादन सीपीयू में बहुत तेज हार्डवेयर गुणा (कम विलंबता और उच्च प्रवाह) है, इसलिए लाभ बहुत छोटा है। एएमडी बुलडोजर-परिवार थोड़ा धीमा है, खासकर 64-बिट के लिए। इंटेल सीपीयू, और एएमडी राईजन पर, दो पारियां थोड़ी कम विलंबता लेकिन गुणा से अधिक निर्देश हैं (जिससे निम्न थ्रूपुट हो सकता है):

imul edi, [row], 320    ; 3 cycle latency from [row] being ready
add  edi, [column]      ; 1 cycle latency (from [column] and edi being ready).
; edi = [row]*(256+64) + [column],  in 4 cycles from [row] being ready.

बनाम

mov edi, [row]
shl edi, 6               ; row*64.   1 cycle latency
lea edi, [edi + edi*4]   ; row*(64 + 64*4).  1 cycle latency
add edi, [column]        ; 1 cycle latency from edi and [column] both being ready
; edi = [row]*(256+64) + [column],  in 3 cycles from [row] being ready.

कंपाइलर आपके लिए यह करेंगे: देखें कि कैसे जीसीसी, क्लैंग और माइक्रोसॉफ्ट विजुअल C ++ सभी अनुकूलन करते समय शिफ्ट + ली का उपयोग करते हैंreturn 320*row + col;

यहां ध्यान देने वाली सबसे दिलचस्प बात यह है कि x86 में एक शिफ्ट-एंड-ऐड इंस्ट्रक्शन ( LEA) है, जो एक addनिर्देश के रूप में प्रदर्शन के साथ, एक ही समय में छोटे बाएं बदलाव कर सकता है और जोड़ सकता है । एआरएम और भी अधिक शक्तिशाली है: किसी भी निर्देश के एक ऑपरेंड को बाएं या दाएं स्थानांतरित किया जा सकता है। एक संकलन-समय-स्थिरांक द्वारा स्केलिंग जिसे एक शक्ति -2 के रूप में जाना जाता है, एक गुणा से भी अधिक कुशल हो सकता है।


ठीक है, आधुनिक दिनों में वापस ... अब अधिक उपयोगी कुछ बिटशफ्टिंग का उपयोग 16-बिट पूर्णांक में दो 8-बिट मानों को संग्रहीत करने के लिए होगा। उदाहरण के लिए, C # में:

// Byte1: 11110000
// Byte2: 00001111

Int16 value = ((byte)(Byte1 >> 8) | Byte2));

// value = 000011111110000;

C ++ में, कंपाइलर्स को आपके लिए ऐसा करना चाहिए यदि आपने structदो 8-बिट सदस्यों के साथ उपयोग किया है , लेकिन व्यवहार में वे हमेशा नहीं होते हैं।


7
इंटेल प्रोसेसर (और बहुत से अन्य) पर इसका विस्तार करते हुए ऐसा करना तेज़ है: int c, d; ग = घ << 2; इससे आगे: c = 4 * d; कभी-कभी, यहां तक ​​कि "सी = डी << 2 + डी << 1" "सी = 6 * डी" की तुलना में तेज़ होता है !! मैंने डॉस युग में ग्राफिक कार्यों के लिए बड़े पैमाने पर इन ट्रिक्स का इस्तेमाल किया, मुझे नहीं लगता कि वे अब इतने उपयोगी हैं ...
जो Pineda

4
@ नाम: काफी नहीं, आजकल यह वीडियो-कार्ड के फर्मवेयर है जिसमें सीपीयू के बजाय जीपीयू द्वारा निष्पादित किए जाने वाले कोड जैसे शामिल हैं। तो सैद्धांतिक रूप से आपको ग्राफिक फ़ंक्शंस के लिए इस तरह (या कार्मैक के काले-जादू उलटा जड़ फ़ंक्शन) कोड को लागू करने की आवश्यकता नहीं है :-)
जो Pineda

2
@JoePineda @james संकलक लेखक निश्चित रूप से उनका उपयोग कर रहे हैं। अगर आप लिखेंगे c=4*dतो आपको एक शिफ्ट मिलेगा। यदि आप लिखते हैं k = (n<0)कि बदलाव के साथ भी किया जा सकता है: k = (n>>31)&1एक शाखा से बचने के लिए। निचला रेखा, कंपाइलरों की चतुराई में सुधार का मतलब है कि सी कोड में इन चालों का उपयोग करना अब अनावश्यक है, और वे पठनीयता और पोर्टेबिलिटी से समझौता करते हैं। यदि आप SSE वेक्टर कोड लिख रहे हैं, तो उन्हें जानना बहुत अच्छा है; या किसी भी स्थिति में जहाँ आपको इसकी आवश्यकता है और वहाँ एक चाल है जो संकलक उपयोग नहीं कर रहा है (जैसे जीपीयू कोड)।
ग्रैग्गो

2
एक और अच्छा उदाहरण: बहुत ही सामान्य बात यह है if(x >= 1 && x <= 9)कि if( (unsigned)(x-1) <=(unsigned)(9-1)) दो सशर्त परीक्षणों को बदलने के रूप में किया जा सकता है एक बड़ी गति लाभ हो सकता है; विशेष रूप से जब यह शाखाओं के बजाय समर्पित निष्पादन की अनुमति देता है। मैंने इसे सालों तक इस्तेमाल किया (जहां उचित था) जब तक मैंने 10 साल पहले abt पर ध्यान नहीं दिया था कि कंपाइलर ने इस बदलाव को ऑप्टिमाइज़र में करना शुरू कर दिया था, तब मैं रुक गया। अभी भी यह जानना अच्छा है, क्योंकि ऐसी ही स्थितियां हैं, जहां कंपाइलर आपके लिए बदलाव नहीं कर सकता। या यदि आप एक संकलक पर काम कर रहे हैं।
ग्रैग्गो

3
क्या कोई कारण है कि आपका "बाइट" केवल 7 बिट्स है?
मेसन Watmough

103

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

ग्राफिक्स प्रोग्रामिंग में एक सरल वास्तविक उदाहरण यह है कि 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) ...;

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

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

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

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

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

1
0x7e0 11111100000 के समान है जो दशमलव में 2016 है।
साहिद

50

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

बिट शिफ्टिंग का उपयोग अक्सर निम्न-स्तरीय ग्राफिक्स प्रोग्रामिंग में किया जाता है। उदाहरण के लिए, किसी दिए गए पिक्सेल रंग मान को 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

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

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

इस बार एन्कोडिंग या की तरह छवि प्रारूप डीकोड करने के लिए प्रयोग किया जाता है jpg, pngआदि


क्या यह आसान नहीं है कि आप अपना ओरिजिनल कास्ट करें, 32bit cl_uint कहें, जैसे कि cl_uchar4 और कुछ बाइट एक्सेस करें जो आप सीधे * .s2 के रूप में चाहते हैं?
डेविड एच पैरी

27

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

char x = -1;
x >> 1;

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

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


4
यदि मैं इसे सही ढंग से याद करता हूं, तो एएनएसआई सी मानक स्पष्ट रूप से कहता है कि यह कार्यान्वयन-निर्भर है, इसलिए आपको यह देखने के लिए अपने संकलक के दस्तावेज की जांच करने की आवश्यकता है कि यदि आप अपने कोड पर हस्ताक्षर किए गए पूर्णांक को राइट-शिफ्ट करना चाहते हैं तो इसे कैसे लागू किया जाए।
जो पीपा

हां, मैं सिर्फ एएनएसआई मानक पर जोर देना चाहता था ऐसा खुद कहते हैं, यह ऐसा मामला नहीं है जहां विक्रेता केवल मानक का पालन नहीं कर रहे हैं या यह मानक इस कण मामले के बारे में कुछ नहीं कहता है।
जो पाइदा

22

मैं केवल टिप्स और ट्रिक्स लिख रहा हूं। यह परीक्षण और परीक्षा में उपयोगी हो सकता है।

  1. n = n*2: n = n<<1
  2. n = n/2: n = n>>1
  3. जाँच रहा है कि n 2 की शक्ति है (1,2,4,8, ...): जाँच करें !(n & (n-1))
  4. हो रही एक्स वीं की सा n:n |= (1 << x)
  5. जाँच करना कि क्या x सम या विषम है: x&1 == 0(सम)
  6. X के n वें बिट को टॉगल करें :x ^ (1<<n)

कुछ और भी होने चाहिए जो आप अब तक जानते हैं?
ryyker

@ryyker मैंने कुछ और जोड़े हैं। मैं इसे अद्यतन रखने की कोशिश करूंगा :)
रवि प्रकाश

क्या x और n 0 अनुक्रमित हैं?
रेगेगिटेरिटी

विज्ञापन 5 .: यदि यह एक ऋणात्मक संख्या है तो क्या होगा?
पीटर मोर्टेंसन

तो, क्या हम बाइनरी में 10 को दशमलव में 10 की तरह समाप्त कर सकते हैं? और बिट शिफ्टिंग दशमलव में किसी अन्य संख्या के पीछे एक और संख्या को जोड़ने या प्रतिस्थापित करने जैसा है?
विली सात्रियो नुग्रोहो

8

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

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

(long) 4 >> 65

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

(long) 4 >> (65 % 64)

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


हुह, दिलचस्प! सी में, यह तकनीकी रूप से अपरिभाषित व्यवहार हैgcc 5.4.0एक चेतावनी देता है, लेकिन 25 >> 65 के लिए देता है ; भी।
pizzapants184

2

पायथन में कुछ उपयोगी बिट संचालन / जोड़तोड़।

मैंने पायथन में रवि प्रकाश के जवाब को लागू किया ।

# Basic bit operations
# Integer to binary
print(bin(10))

# Binary to integer
print(int('1010', 2))

# Multiplying x with 2 .... x**2 == x << 1
print(200 << 1)

# Dividing x with 2 .... x/2 == x >> 1
print(200 >> 1)

# Modulo x with 2 .... x % 2 == x & 1
if 20 & 1 == 0:
    print("20 is a even number")

# Check if n is power of 2: check !(n & (n-1))
print(not(33 & (33-1)))

# Getting xth bit of n: (n >> x) & 1
print((10 >> 2) & 1) # Bin of 10 == 1010 and second bit is 0

# Toggle nth bit of x : x^(1 << n)
# take bin(10) == 1010 and toggling second bit in bin(10) we get 1110 === bin(14)
print(10^(1 << 2))

-3

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

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

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

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

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