संभावना है कि आपको आमतौर पर अपनी दैनिक नौकरी में किसी बिटवाइज़ गणित की आवश्यकता नहीं होती। Ruby के बिटवाइज़ AND और OR ऑपरेटर (& और |) शायद उद्देश्य से अधिक दुर्घटना से उपयोग किए जाते हैं। किसने गलती से && के बजाय & टाइप नहीं किया है?
लेकिन अगर आप C या असेंबलर जैसी निचले स्तर की भाषाओं में प्रोग्रामिंग करते हुए बड़े हुए हैं, या मेरे मामले में टर्बो पास्कल तो आपने शायद कम से कम कुछ बिट ट्विडलिंग की है।
समस्याओं के बिटवाइज़ समाधान सिर्फ कूल हैं। यदि आप किसी समस्या को हल करने में सक्षम हैं जो कंप्यूटर करने में सक्षम सबसे बुनियादी ऑपरेशन (बाइनरी गणित) का उपयोग करता है, तो यह उससे अधिक सुंदर नहीं हो सकता।
Ruby में बाइनरी के साथ काम करना
आप शायद जानते हैं कि आपके कंप्यूटर में सब कुछ संख्याओं के रूप में दर्शाया गया है, और वे संख्याएं बाइनरी प्रारूप में हैं। लेकिन यह Ruby में कैसा दिखता है? इस उदाहरण में, मैं अक्षर "a" के लिए ASCII कैरेक्टर कोड देखने के लिए Ruby का उपयोग कर रहा हूँ, फिर इसे "बाइनरी" के रूप में प्रिंट कर रहा हूँ।
आप Ruby में `ord` मेथड का उपयोग करके किसी कैरेक्टर का ASCII कोड प्राप्त कर सकते हैं, और फिर इसे "बाइनरी" प्रतिनिधित्व के रूप में प्रिंट करने के लिए `printf` का उपयोग कर सकते हैं।
हालांकि हमें संख्या को बाइनरी में प्रदर्शित करने के लिए printf जैसे मेथड का उपयोग करना पड़ता है, यह हमेशा बाइनरी थी। आप `0b11111111` जैसे सिंटैक्स का उपयोग करके अपने Ruby कोड के अंदर बाइनरी संख्याएं लिख सकते हैं।
अपने कोड में बाइनरी लिटरल जोड़ने के लिए, स्ट्रिंग को 0b से पूर्वनिर्धारित करें। तो `0b11111111`
बाइनरी मानों में हेरफेर करना
अब जब हम जानते हैं कि Ruby में बाइनरी लिटरल का उपयोग कैसे करें, तो हम उनके साथ खेलना शुरू कर सकते हैं। ऐसा करने के लिए हम बिटवाइज़ ऑपरेटर्स का उपयोग करेंगे।
आप शायद && जैसे बूलियन ऑपरेटर्स के साथ सहज हैं। एक्सप्रेशन a && b केवल तभी सही लौटाता है जब a और b दोनों सही हों। बिटवाइज़ ऑपरेटर्स बहुत समान हैं।
उदाहरण के लिए, बिटवाइज़ AND दो मान लेता है और उनकी तुलना बिट दर बिट करता है। यदि दोनों बिट्स 1 हैं, तो यह संबंधित आउटपुट बिट को 1 पर सेट करता है। यदि नहीं, तो इसे शून्य पर सेट करता है। इसलिए यदि आपके पास आठ बिट्स हैं, तो आपके पास आठ अलग-अलग AND होंगे। यदि आपके पास एक बिट है, तो आपके पास एक AND है। निम्नलिखित उदाहरण एकल बिट का उपयोग करके इसे चित्रित करते हैं।
एकल बिट के साथ बिटवाइज़ AND ऑपरेशन का उदाहरण।
यह दो बिट्स के लिए समान तरीके से काम करता है।
बिट्स के प्रत्येक जोड़े को अलग से AND किया जाता है
Ruby के बिटवाइज़ ऑपरेटर्स
प्रत्येक प्रोग्रामिंग भाषा इस बिटवाइज़ ऑपरेटर्स के सेट के साथ आती है। यदि आप उनसे परिचित नहीं हैं, तो IRB में उन्हें आज़माने में थोड़ा समय बिताएं। एक बार जब आप उन्हें सीख लेते हैं, तो आप जीवन भर उनका उपयोग कर सकेंगे।
| & | बिटवाइज़ AND ऑपरेटर परिणाम के बिट को 1 पर सेट करता है यदि यह दोनों इनपुट मानों में 1 है | 0b1010 & 0b0111 == 0b0010 |
| | | बिटवाइज़ OR ऑपरेटर परिणाम के बिट को 1 पर सेट करता है यदि यह किसी भी इनपुट मान में 1 है | 0b1010 | 0b0111 == 0b1111 |
| ^ | बिटवाइज़ XOR ऑपरेटर परिणाम बिट को 1 पर सेट करता है यदि यह किसी भी इनपुट मान में 1 है, लेकिन दोनों में नहीं | 0b1010 | 0b0111== 0b1101 |
| ~ | बिटवाइज़ इनवर्स ऑपरेटर परिणाम बिट को 0 पर सेट करता है यदि इनपुट 1 है और इसके विपरीत | ~0b1010 == 0b0101 |
| << | बिटवाइज़ लेफ्ट शिफ्ट ऑपरेटर. इनपुट बिट्स को निर्दिष्ट संख्या में स्थानों से बाएं ले जाता है। | 0b1010 << 4== 0b10100000 |
| >> | बिटवाइज़ राइट शिफ्ट ऑपरेटर. इनपुट बिट्स को निश्चित संख्या में स्थानों से दाएं ले जाता है | 0b1010 >> 4 == 0b0000 |
व्यावहारिक उपयोग: कॉन्फ़िगरेशन फ्लैग्स
ठीक है, ठीक है, यह बिटवाइज़ गणित का सबसे उबाऊ उपयोग होना चाहिए। लेकिन यह सबसे आम में से एक भी है। यदि आपको कभी Java या C या C++ में लिखे कोड के साथ इंटरफेस करना पड़ता है तो आप अंततः बिटवाइज़ कॉन्फ़िगरेशन फ्लैग्स का सामना करेंगे।
कल्पना करें कि यह 1996 है और आपने अभी-अभी स्क्रैच से एक डेटाबेस सिस्टम बनाया है। चूंकि आपने अभी-अभी फिल्म Hackers देखी है, आप मानते हैं कि किसी प्रकार का एक्सेस कंट्रोल बनाना अच्छा हो सकता है।
आपके DB में 8 क्रियाएं हैं जो एक उपयोगकर्ता कर सकता है: पढ़ना, लिखना, हटाना, और पांच और। आप उनमें से प्रत्येक को स्वतंत्र रूप से सेट करने में सक्षम होना चाहते हैं। आपके पास एक उपयोगकर्ता हो सकता है जो पढ़ सकता है लेकिन लिख या हटा नहीं सकता। आपके पास एक हो सकता है जो लिख सकता है लेकिन टेबल ड्रॉप नहीं कर सकता।
इन कॉन्फ़िगरेशन फ्लैग्स को स्टोर करने का सबसे कुशल तरीका उन्हें एक बाइट में बिट्स के रूप में स्टोर करना है। फिर एक उपयोगकर्ता बस उन्हें एक साथ OR करेगा ताकि वे अनुमतियों का जो भी संयोजन चाहते हैं वह बना सकें।
MYDB_READ = 0b00000001 # इन संख्याओं को बिटमास्क कहा जाता है MYDB_WRITE = 0b00000010 MYDB_DELETE = 0b00000100 MYDB_INDEX = 0b00001000 user.permissions = MYDB_READ | MYDB_WRITE
वैसे, यह वास्तव में इसी तरह है जैसे यूनिक्स फ़ाइल अनुमतियों को संभाला जाता है। यदि आपने कभी सोचा है कि आपको केवल एक फ़ाइल को रीड-ओनली बनाने के लिए एक मैजिक नंबर का उपयोग क्यों करना पड़ता है, तो अब आप जानते हैं।
कॉन्फ़िगरेशन विकल्पों को बिट्स में स्टोर करना बहुत उपयोगी नहीं होगा जब तक कि आप यह पता नहीं लगा सकते कि कोई विशेष बिट सेट है या नहीं। ऐसा करने के लिए, आप बस बिटवाइज़ AND का उपयोग करते हैं।
यह निर्धारित करने के लिए बिटमास्क के साथ AND का उपयोग करें कि कोई बिट सेट है या नहीं।
कम व्यावहारिक उपयोग (जब तक कि आप C प्रोग्रामर न हों)
अब आइए कुछ मैथेमैजिकल सामान करते हैं।
ऐतिहासिक रूप से, बिट मैनिपुलेशन का उपयोग तब किया जाता था जब आप किसी गणना से मिलीसेकंड के अंतिम अंश को निचोड़ने की कोशिश कर रहे थे। तो जैसा कि आप कल्पना कर सकते हैं, इसका उपयोग ग्राफिक्स प्रोग्रामर्स और अन्य लोगों द्वारा बहुत किया जाता था जिन्हें हर चीज से ऊपर प्रदर्शन की आवश्यकता होती थी।
तो इस तरह की तकनीकें रोजमर्रा के Ruby विकास के लिए व्यावहारिक नहीं हैं। लेकिन वे अभी भी एक मजेदार सीखने का अभ्यास हैं, और अगर आप एम्बेडेड सिस्टम प्रोग्रामिंग जैसी चीजों में आते हैं तो वैध रूप से उपयोगी हो सकते हैं। अधिक गहन उपचार के लिए, बिट ट्विडलिंग हैक्स की इस सूची को देखें।
दो की घात से गुणा और भाग करना
आइए संख्याओं 1, 2, 4, और 8 के बाइनरी प्रतिनिधित्व को देखें। जैसा कि आप देख सकते हैं, संख्या को दोगुना करना सभी बिट्स को एक स्थान बाएं शिफ्ट करने के बराबर है। इसी तरह, संख्या को आधा करना दाएं शिफ्ट करने के समान है।
1, 2, 4, 8 के बाइनरी प्रतिनिधित्व
यदि आपको याद होगा, हमारे पास लेफ्ट शिफ्ट और राइट शिफ्ट ऑपरेटर्स हैं। इसका मतलब है कि हम केवल बिट्स को शिफ्ट करके दो की घात से गुणा और भाग कर सकते हैं।
आप बिटवाइज़ शिफ्ट ऑपरेटर्स का उपयोग करके दो की घात से गुणा या भाग कर सकते हैं
दो धनात्मक पूर्णांकों का औसत
आप दो पूर्णांकों का बुनियादी जोड़ इस तरह कर सकते हैं: (x+y) == (x&y)+(x|y) == (x^y)+2*(x&y)। औसत की गणना करने के लिए, आपको बस दो से भाग करने की थोड़ी आवश्यकता है, जिसे आप राइट शिफ्ट ऑपरेटर के माध्यम से प्राप्त कर सकते हैं।
आप दो धनात्मक पूर्णांकों का औसत इस तरह निकाल सकते हैं: (x&y)+((x^y)>>1)
त्वरित व्युत्क्रम वर्गमूल
मैं बिट ट्विडलिंग पर एक ब्लॉग पोस्ट नहीं कर सकता बिना सबसे प्रसिद्ध उदाहरणों में से एक को शामिल किए। वह है 1999 के क्वेक 3 एरिना स्रोत कोड से जॉन कार्मैक का त्वरित व्युत्क्रम वर्गमूल सन्निकटन। एल्गोरिदम उनका नहीं है, लेकिन सबसे प्रसिद्ध कार्यान्वयन उनका है।
मैं इसे सीधे Ruby में पोर्ट करने का प्रयास नहीं करने जा रहा हूँ, क्योंकि यह एक फ्लोटिंग पॉइंट संख्या के बाइनरी प्रतिनिधित्व का निर्माण करके काम करता है जिस तरह से C से Ruby में सीधे अनुवाद योग्य नहीं है।
float Q_rsqrt( float number ) { long i; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; y = number; i = * ( long * ) &y; // evil floating point bit level hacking i = 0x5f3759df - ( i >> 1 ); // what the fuck? y = * ( float * ) &i; y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration // y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed return y; }