रूबी 2.4 ने Fixnum और Bignum को एक ही क्लास (Integer) में मर्ज कर दिया, इसलिए मुझे लगता है कि यह रूबी में विभिन्न नंबर टाइप्स की समीक्षा करने का सही समय है!
आज हम इसी के बारे में बात करेंगे 🙂
नंबर टाइप्स का अवलोकन
आइए रूबी में सभी नंबर-संबंधी क्लासेस के क्लास हायरार्की पर एक नज़र डालते हैं:
Numeric Integer Fixnum Bignum Float Complex Rational BigDecimal (Standard Library)
जैसा कि आप देख सकते हैं, Numeric क्लास सभी नंबर क्लासेस की पेरेंट है। याद रखें कि आप किसी भी क्लास के पेरेंट क्लासेस का पता लगाने के लिए ancestors मेथड का उपयोग कर सकते हैं।
उदाहरण:
Fixnum.ancestors - Fixnum.included_modules [Fixnum, Integer, Numeric, Object, BasicObject]
अब इन क्लासेस को टेबल के रूप में देखते हैं:
| क्लास | विवरण | उदाहरण |
|---|---|---|
| Integer | Fixnum और Bignum की पेरेंट क्लास |
1 |
| Fixnum | वे पूर्णांक जो OS इंटीजर टाइप में फिट होते हैं (32 या 64 बिट्स) | 1 |
| Bignum | बड़ी संख्याओं के लिए उपयोग किया जाता है | 111111111111 |
| Float | असटीक दशमलव संख्याएं | 5.0 |
| Complex | काल्पनिक संख्याओं वाले गणित के लिए उपयोग किया जाता है | (1+0i) |
| Rational | भिन्नों को दर्शाने के लिए उपयोग किया जाता है | (2/3) |
| BigDecimal | सटीक दशमलव संख्याएं | 3.0 |
फ्लोट की असटीकता
आधिकारिक रूबी डॉक्यूमेंटेशन में Float क्लास को "असटीक" बताया गया है।
ऐसा क्यों है?
मैं आपको एक उदाहरण दिखाता हूं:
0.2 + 0.1 == 0.3 # false
यह false क्यों है?
आइए 0.2 + 0.1 के परिणाम को देखते हैं:
0.30000000000000004
बिल्कुल! यही वह असटीकता है जिसका हम मतलब रखते हैं।
ऐसा इसलिए होता है क्योंकि फ्लोट को स्टोर करने का तरीका ऐसा है। यदि आपको ऐसी दशमलव संख्याएं चाहिए जो हमेशा सटीक हों, तो आप BigDecimal क्लास का उपयोग कर सकते हैं।
Float बनाम BigDecimal
BigDecimal एक ऐसी क्लास है जो आपको मनमानी-परिशुद्धता (arbitrary-precision) वाली दशमलव संख्याएं देती है।
उदाहरण:
require 'bigdecimal' BigDecimal("0.2") + BigDecimal("0.1") == 0.3 # true
हम हमेशा BigDecimal का उपयोग क्यों नहीं करते? क्योंकि यह बहुत धीमा है!
यहां एक बेंचमार्क है:
Calculating ------------------------------------- bigdecimal 21.559k i/100ms float 79.336k i/100ms ------------------------------------------------- bigdecimal 311.721k (± 7.4%) i/s - 1.552M float 3.817M (±11.7%) i/s - 18.803M Comparison: float: 3817207.2 i/s bigdecimal: 311721.2 i/s - 12.25x slower
BigDecimal, Float से 12 गुना धीमा है, और इसीलिए यह डिफ़ॉल्ट नहीं है 🙂
Fixnum बनाम Bignum
इस सेक्शन में, मैं रूबी 2.4 से पहले Fixnum और Bignum के बीच के अंतरों का पता लगाना चाहता हूं।
आइए कुछ कोड से शुरू करते हैं:
1.class # Fixnum 100000000000.class # Bignum
रूबी हमारे लिए सही क्लास बनाता है, और जब आवश्यक हो तो यह स्वचालित रूप से एक Fixnum को Bignum में प्रोमोट कर देता है।
नोट: यदि आपके पास 64-बिट रूबी इंटरप्रेटर है, तो
Bignumऑब्जेक्ट प्राप्त करने के लिए आपको एक बड़ी संख्या की आवश्यकता हो सकती है।
हमें अलग-अलग क्लासेस की आवश्यकता क्यों है? इसका उत्तर यह है कि बड़ी संख्याओं के साथ काम करने के लिए आपको एक अलग इम्प्लीमेंटेशन की आवश्यकता होती है, और बड़ी संख्याओं के साथ काम करना धीमा होता है, इसलिए हम Float बनाम BigDecimal जैसी ही स्थिति में पहुंच जाते हैं।
Fixnum के विशेष गुण
Fixnum क्लास के कुछ विशेष गुण भी हैं। उदाहरण के लिए, ऑब्जेक्ट आईडी की गणना एक फॉर्मूला का उपयोग करके की जाती है।
1.object_id # 3 20.object_id # 41
फॉर्मूला है: (number * 2) + 1।
लेकिन इसमें और भी बहुत कुछ है, जब आप एक Fixnum का उपयोग करते हैं तो कोई ऑब्जेक्ट बिल्कुल नहीं बनाया जाता है। Fixnum में स्टोर करने के लिए कोई डेटा नहीं होता, क्योंकि वैल्यू ऑब्जेक्ट आईडी से ही प्राप्त होती है।
यह केवल एक इम्प्लीमेंटेशन डिटेल है, लेकिन मुझे लगता है कि यह जानना दिलचस्प है 🙂
MRI (Matz's Ruby Interpreter) वैल्यू और ऑब्जेक्ट आईडी के बीच कन्वर्ट करने के लिए इन दो मैक्रोज़ का उपयोग करता है:
INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG)) FIX2LONG(x) ((long)RSHIFT((SIGNED_VALUE)(x),1))
यहां जो होता है उसे "बिट शिफ्टिंग" कहा जाता है, जो सभी बिट्स को बाएं या दाएं ले जाता है।
एक पोजीशन बाएं शिफ्ट करना 2 से गुणा करने के बराबर है और इसीलिए फॉर्मूला (number * 2) + 1 है। +1 FIXNUM_FLAG से आता है।
इसके विपरीत, Bignum एक सामान्य क्लास की तरह काम करता है और सामान्य ऑब्जेक्ट आईडी का उपयोग करता है:
111111111111111.object_id # 23885808
इस सबका मतलब है कि इंटरप्रेटर लेवल पर Fixnum ऑब्जेक्ट्स सिम्बल्स के करीब हैं कि वे कैसे काम करते हैं, जबकि Bignum ऑब्जेक्ट्स स्ट्रिंग्स के करीब हैं।
रूबी 2.4 में इंटीजर्स
चूंकि रूबी 2.4 में Fixnum और Bignum डिप्रेकेटेड हैं, लेकिन पर्दे के पीछे वे अभी भी उसी तरह काम करते हैं।
रूबी एक टाइप से दूसरे टाइप पर स्वचालित रूप से स्विच करता है।
क्लास बदले बिना।
इसका मतलब है कि छोटी Integer संख्याएं अभी भी उसी तरह काम करती हैं जैसे Fixnum।
सारांश
इस पोस्ट में, आपने रूबी में मौजूद विभिन्न नंबर-संबंधी क्लासेस के बारे में सीखा।
आपने सीखा कि फ्लोट्स असटीक होते हैं और यदि सटीकता प्रदर्शन से कहीं अधिक महत्वपूर्ण है तो आप BigDecimal का उपयोग कर सकते हैं। आपने यह भी सीखा कि इंटरप्रेटर लेवल पर Fixnum ऑब्जेक्ट्स विशेष होते हैं, लेकिन Bignum सामान्य ऑब्जेक्ट्स होते हैं।
यदि आपको यह पोस्ट दिलचस्प लगी तो नीचे दिए गए फॉर्म में मेरे न्यूज़लेटर के लिए साइन-अप करना न भूलें 🙂