1 पॉइंट द्वारा GN⁺ 5 시간 전 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • ASCII में Z को 90 और a को 97 पर रखा गया है, और इनके बीच के 6 अक्षरों की वजह से uppercase और lowercase कोड का अंतर 32 बनता है
  • 32 2^5 है, इसलिए A 65 और a 97 जैसी corresponding uppercase/lowercase जोड़ी में हमेशा सिर्फ 00100000 वाला एक bit अलग होता है
  • इस arrangement की वजह से 32 के bitwise complement के साथ AND करने पर uppercase, 32 के साथ OR करने पर lowercase, और 32 के साथ XOR करने पर case toggle किया जा सकता है
  • alphabet का क्रम character code पर 31 के साथ AND करके, यानी सिर्फ निचले 5 bits बचाकर निकाला जा सकता है; A/a 1 और Z/z 26 बनते हैं
  • ASCII एक शुरुआती 7-bit character encoding है जो सिर्फ 128 code points को दर्शाती है, और आज इस्तेमाल होने वाले Unicode के पहले 128 code points ASCII जैसे ही हैं

ASCII arrangement और 32 का अंतर

  • ASCII table में uppercase Z का code value 90 है, और lowercase a उसे तुरंत follow नहीं करता बल्कि 97 पर रखा गया है
  • इनके बीच [ \ ] ^ _ ` ये 6 characters हैं
  • अंग्रेज़ी alphabet में 26 अक्षर हैं, और इन 6 characters को जोड़ने पर 26 + 6 = 32 होता है
  • 32, 2^5 के बराबर है, इसलिए uppercase और lowercase की corresponding mapping को एक खास bit के अंतर के हिसाब से align किया गया है
  • उदाहरण के लिए A 65 यानी 01000001 है, और a 97 यानी 01100001; दोनों के बीच का अंतर 32 है

ASCII और Unicode का संबंध

  • ASCII शुरुआती character encoding तरीकों में से एक है और सिर्फ 7 bits का उपयोग करके 2^7 = 128 code points दर्शाता है
  • 128 code points इंसानों द्वारा उपयोग की जाने वाली सभी लिपियों और अक्षरों को समेटने के लिए पर्याप्त नहीं हैं, खासकर चीनी जैसी भाषाओं के लिए जिनमें हज़ारों नहीं बल्कि दसियों हज़ार अक्षर होते हैं
  • आज standard character set के रूप में Unicode इस्तेमाल होता है, और इसके कई encodings हैं जैसे UTF-8 और UTF-16
  • Unicode के पहले 128 code points ASCII के समान हैं

uppercase और lowercase को अलग करने वाला 5वाँ bit

  • uppercase और उसके corresponding lowercase को binary में तुलना करें, तो हमेशा 32 वाले bit में बदलाव होता है
65  = 01000001 = A
97  = 01100001 = a

66  = 01000010 = B
98  = 01100010 = b

67  = 01000011 = C
99  = 01100011 = c
  • 32 binary में 00100000 है, और यही एक bit uppercase और lowercase का अंतर बनाता है
  • ASCII में alphabet की arrangement ऐसी है कि bit operations से case conversion आसान हो जाता है

bit operations से uppercase/lowercase संभालना

  • uppercase में बदलना

    • किसी character को uppercase बनाना हो तो 32 के bitwise complement के साथ bitwise AND किया जाता है
0 1 1 0 0 0 0 1 (97 = 'a')
& 1 1 0 1 1 1 1 1 (mask)
-------------------
0 1 0 0 0 0 0 1 (65 = 'A')
  • a पर लागू करने पर 97, 65 में बदल जाता है और A बनता है
  • जो character पहले से uppercase A है, उस पर भी यही operation करने पर वह A ही रहता है
  • lowercase में बदलना

    • किसी character को lowercase बनाना हो तो 32 के साथ bitwise OR किया जाता है
0 1 0 0 0 0 0 1 (65 = 'A')
| 0 0 1 0 0 0 0 0 (32)
-------------------
0 1 1 0 0 0 0 1 (97 = 'a')
  • A पर लागू करने पर 65, 97 में बदल जाता है और a बनता है
  • जो character पहले से lowercase a है, उस पर भी यही operation करने पर वह a ही रहता है
  • case toggle

    • uppercase/lowercase को उलटने के लिए 32 के साथ bitwise XOR किया जाता है
0 1 1 0 0 0 0 1 (97 = 'a')
^ 0 0 1 0 0 0 0 0 (32)
-------------------
0 1 0 0 0 0 0 1 (65 = 'A')

0 1 0 0 0 0 0 1 (65 = 'A')
^ 0 0 1 0 0 0 0 0 (32)
-------------------
0 1 1 0 0 0 0 1 (97 = 'a')
  • a, A में और A, a में बदल जाता है

निचले 5 bits से alphabet का क्रम निकालना

  • alphabet का क्रम character code पर 31 के साथ bitwise AND करके निकाला जा सकता है
0 1 0 0 0 0 0 1 (65 = 'A')
& 0 0 0 1 1 1 1 1 (31)
-------------------
0 0 0 0 0 0 0 1 (1)

0 1 1 1 1 0 1 0 (122 = 'z')
& 0 0 0 1 1 1 1 1 (31)
-------------------
0 0 0 1 1 0 1 0 (26)
  • 31, binary में 00011111 है, इसलिए यह आगे के bits मिटाकर सिर्फ निचले 5 bits छोड़ता है
  • ASCII में alphabet characters के निचले 5 bits alphabet की position से मेल खाते हैं
  • A/a का अंत 00001 से होता है इसलिए 1 मिलता है, B/b का 00010 से इसलिए 2, और Z/z का 11010 से इसलिए 26 मिलता है
  • ASCII character code में c & 31, c % 32 के बराबर है
  • क्योंकि 32, 2 की घात है, 31 से masking करने पर 32-unit के blocks हट जाते हैं और सिर्फ बाकी हिस्सा बचता है
'A' = 65  → 65 % 32 = 1
'B' = 66  → 66 % 32 = 2
...
'Z' = 90  → 90 % 32 = 26
'a' = 97  → 97 % 32 = 1
'b' = 98  → 98 % 32 = 2
...
'z' = 122 → 122 % 32 = 26

1 टिप्पणियां

 
GN⁺ 5 시간 전
Lobste.rs की राय
  • व्याख्या ठीक है, लेकिन मुझे लगता है कि https://garbagecollected.org/2017/01/31/four-column-ascii/ इसे बेहतर समझाता है
    मामला सिर्फ Shift का नहीं है, Ctrl भी जुड़ा है। उदाहरण के लिए Tab, Ctrl-I है, क्योंकि I 1001001 है और Ctrl पहले बिट को mask कर देता है, जिससे Tab का 0001001 बचता है

  • अगर 1960 के दशक के निर्माताओं की तरह इलेक्ट्रॉनिक logic के बजाय electromechanical logic इस्तेमाल की जाए, तो bit paired keyboard को लागू करना कहीं आसान होता
    Shift key के लिए ASCII अक्षर में सिर्फ एक bit toggle करना होता है। आज हर keyboard में general-purpose CPU होता है और logic लगभग मुफ़्त है, लेकिन जब general-purpose computer एक पूरे कमरे के बराबर होते थे, तब ऐसा समाधान कहीं ज़्यादा महँगा पड़ता था

  • लेख यह बताता है कि ASCII layout के पीछे की प्रेरणा यह थी कि uppercase/lowercase conversion को bit operations से कुशलता से लागू किया जा सके, लेकिन इसका महत्व ऐतिहासिक रूप से चाहे जो रहा हो, आज के संदर्भ में यह काफ़ी सीमित लगता है
    a→A conversion सिर्फ साधारण text में काम करता है, और भले ही ISO-8859-1 या Unicode इस layout को ü, ç जैसे अक्षरों तक कुछ हद तक बढ़ाते हों, uppercase/lowercase conversion locale, context और समय के अनुसार बदलता है। ß या ï के सही uppercase/lowercase mapping भाषा, नियामक संस्थाओं, उपयोग क्षेत्र और समय पर निर्भर करते हैं
    Unicode https://www.unicode.org/charts/case/ जैसी case mapping और folding tables देता है, जो आम मामलों में काफ़ी क़रीबी जवाब देते हैं, लेकिन यह ऐसा मसला है जिसमें मानवीय नीतियाँ दखल देती हैं, इसलिए इसकी complexity व्यवहार में लगभग अनंत है और सही परिणाम के लिए custom software की ज़रूरत पड़ सकती है
    आज अगर यह गारंटी नहीं दी जा सकती कि सब कुछ Unicode के शुरुआती 2⁷ code points तक ही सीमित रहेगा, तो 0b0010_0000 offset आसानी से टूट जाता है, और single bit operation से महँगा code path अनिवार्य हो जाता है। CPython में भी ''.upper unicode_upper{,_impl} के ASCII fast path से गुजरता है, लेकिन व्यवहार में वह branch, inline function, struct access, कई functions और functions, macros से होकर table lookup करता है
    आधुनिक भाषाओं में ''.upper का implementation मोटे तौर पर इसी स्तर की complexity रखेगा, और compiler optimization के बावजूद आधुनिक तरीका single bit operation से महँगा ही होगा। इस design का फ़ायदा शायद केवल ऐसे custom software में साफ़ दिखे, जो raw binary पर arithmetic करे या dtype=uint8 वाले numpy.ndarray में 2⁷ से कम code point Unicode data रखता हो
    मेरी जिज्ञासा यह है: अगर मान लें कि इस design choice की एकमात्र प्रेरणा वही थी जो लेख में बताई गई है, तो उस समय 128-byte lookup table जैसा विकल्प भी मौजूद रहा होगा—तो computing history में ऐसा कौन-सा दौर था जब single bit operation, 128-byte table lookup से ज़्यादा efficient या ज़्यादा feasible था?

    • लंबे समय तक सफल रही mass technology को गहराई से देखें तो इस तरह की bit tricks अक्सर मिलती हैं
      किसी एक समय का design choice, बाद में टूटने वाली assumptions पर टिककर किसी चीज़ का रूप स्थिर कर देता है और आगे के विस्तार को कठिन या असंभव बना देता है। IPv6 पर हाल की लिखाइयों में भी दिखता है कि IPv4 और IPv6 के कुछ फैसले, जो उस समय सही थे, आज बहुत बड़ा बोझ बन गए हैं
      उदार नज़रिए से देखें तो ऐसे फैसले जोखिम और लाभ को तौलकर लिए गए होंगे। जैसे, “अगर एक character को uppercase करने में single bit operation लगे तो यह बहुत तेज़ होगा, इसलिए भविष्य में जापानी users आने पर इसके टूटने का जोखिम उठाना ठीक है”
      आज के नज़रिए से 1976 का एक चुनाव 2026 की ज़िंदगी मुश्किल बनाता है, लेकिन अगर 1976 में आपके पास computer ही नहीं था, तो आपने उसका लाभ कभी पाया ही नहीं और आपके हिस्से सिर्फ नुकसान आया। इस स्वार्थ को थोड़ा अलग रखकर सोचूँ तो जिज्ञासा यह है कि अगर 20 साल बाद भी लोकप्रिय रहने वाला software बनाना हो, तो ऐसी choices की sustainability बेहतर तरीके से कैसे आँकी जाए
    • कई network protocols आज भी ASCII case-insensitive encoding इस्तेमाल करते हैं, इसलिए तेज़ bitwise tolower अब भी उपयोगी है। https://dotat.at/@/2022-06-27-tolower-swar.html
  • कम से कम ASCII में अक्षर लगातार क्रम में हैं। EBCDIC में gap 0x40(64) का है, और ASCII की तुलना में उसका रूप 9-9 अक्षरों की दो पंक्तियाँ और 8 अक्षरों की एक पंक्ति ऊपर-नीचे रखी हुई जैसी है
    https://en.wikipedia.org/wiki/EBCDIC

    • EBCDIC से पहले के 6-bit character codes में भी काफ़ी अजीब चीज़ें थीं। https://en.wikipedia.org/wiki/Six-bit_character_code/…
      5-bit code http://www.quadibloc.com/crypto/images/tele38.gif और, अगर मुझे सही याद है, कुछ CDC peripherals जो बहुत सारे page-switching control characters वाले 6-bit code इस्तेमाल करते थे—उनके बारे में कम ही कहा जाए तो बेहतर है
  • यह याद आ गया कि IRC nicknames ASCII case-insensitive थे, इसलिए foo{ को foo[ जैसा और bar| को bar\ जैसा माना जाता था
    अगर आज भी कुछ clients इस वजह से भ्रमित हो जाते हों, तो मुझे हैरानी नहीं होगी