রুবি ২.৪ সংস্করণে Fixnum এবং Bignum ক্লাস দুটিকে একই ক্লাস (Integer)তে একত্রিত করা হয়েছে, তাই রুবির বিভিন্ন নম্বর টাইপগুলো রিভিউ করার জন্য এটি সঠিক সময়।
রুবিতে সব নম্বর-সম্পর্কিত ক্লাসের ক্লাস হায়ারার্কি দেখি:
Numeric
Integer
Fixnum
Bignum
Float
Complex
Rational
BigDecimal (স্ট্যান্ডার্ড লাইব্রেরি)
আপনি দেখতে পাচ্ছেন, Numeric ক্লাসটি সব নম্বর ক্লাসের প্যারেন্ট। মনে রাখবেন, যেকোনো ক্লাসের প্যারেন্ট ক্লাসগুলো খুঁজে বের করতে ancestors মেথড ব্যবহার করা যায়।
উদাহরণ:
Fixnum.ancestors - Fixnum.included_modules # [Fixnum, Integer, Numeric, Object, BasicObject]
| ক্লাস | বিবরণ | উদাহরণ |
|---|---|---|
| Integer | Fixnum এবং Bignum এর প্যারেন্ট ক্লাস |
1 |
| Fixnum | ওএস ইন্টিজার টাইপে ফিট হওয়া পূর্ণসংখ্যা (৩২ বা ৬৪ বিট) | 1 |
| Bignum | বড় সংখ্যাগুলোর জন্য ব্যবহৃত হয় | 111111111111 |
| Float | অনিশ্চিত দশমিক সংখ্যা | 5.0 |
| Complex | ক্যাল্পনিক সংখ্যার সাথে গাণিতিক কাজের জন্য | (1+0i) |
| Rational | ভগ্নাংশ উপস্থাপনার জন্য | (2/3) |
| BigDecimal | নির্ভুল দশমিক সংখ্যা | 3.0 |
রুবির অফিসিয়াল ডকুমেন্টেশনে Float ক্লাসকে "অনিশ্চিত" (imprecise) বলে বর্ণনা করা হয়েছে। কেন?
একটি উদাহরণ দেখি:
0.2 + 0.1 == 0.3 # false
এটি false কেন? 0.2 + 0.1 এর ফলাফল দেখি:
0.30000000000000004
ঠিকই! এটাই অনিশ্চিততার অর্থ। ফ্লোট কীভাবে সংরক্ষিত হয় তার কারণে এটি হয়। আপনাকে যদি সর্বদা নির্ভুল দশমিক সংখ্যা দরকার হয়, তবে 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 চেয়ে ১২ গুণ ধীর, এবং এটাই ডিফল্ট না হওয়ার কারণ।
এই সেকশনে, রুবি ২.৪ এর আগে Fixnum এবং Bignum এর পার্থক্য নিয়ে আলোচনা করব।
কিছু কোড দিয়ে শুরু করা যাক:
1.class # Fixnum 100000000000.class # Bignum
রুবি স্বয়ংক্রিয়ভাবে সঠিক ক্লাস তৈরি করে, এবং প্রয়োজনে Fixnum-কে Bignum-এ প্রোমোট করে দেয়।
নোট: ৬৪-বিট রুবি ইন্টারপ্রিটার থাকলে
Bignumঅবজেক্ট পেতে বড় সংখ্যা দরকার হতে পারে।
কেন আলাদা ক্লাস দরকার? কারণ বড় সংখ্যার সাথে কাজ করার জন্য আলাদা ইমপ্লিমেন্টেশন লাগে, এবং বড় সংখ্যার সাথে কাজ করা ধীর—Float বনাম BigDecimal এর মতোই পরিস্থিতি।
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))
এখানে "বিট শিফটিং" (bit shifting) হয়, যা সব বিটকে বাম বা ডানে সরায়। এক পজিশন বামে শিফট করা মানে ২ দিয়ে গুণ করা, এবং এটাই ফর্মুলা (number * 2) + 1 হওয়ার কারণ। +1 আসে FIXNUM_FLAG থেকে।
বিপরীতে, Bignum সাধারণ ক্লাসের মতো কাজ করে এবং সাধারণ অবজেক্ট আইডি ব্যবহার করে:
111111111111111.object_id # 23885808
এটি বোঝায় Fixnum অবজেক্টগুলো ইন্টারপ্রেটার লেভেলে সিম্বলের মতো কাজ করে,حين Bignum অবজেক্টগুলো স্ট্রিং-এর মতো।
রুবি ২.৪ থেকে Fixnum এবং Bignum ডিপ্রিকেটেড, কিন্তু পেছনে থেকে তারা একইভাবে কাজ করে।
রুবি স্বয়ংক্রিয়ভাবে এক টাইপ থেকে অন্য টাইপে স্যুইচ করে—ক্লাস পরিবর্তন किए বিনা।
এমনつまり ছোট Integer সংখ্যাগুলো এখনও Fixnum এর মতোই অপারেট করে।
এই পোস্টে আপনি রুবির বিভিন্ন নম্বর-সম্পর্কিত ক্লাস সম্পর্কে জানলেন।
আপনি জানলেন যে ফ্লোট অনিশ্চিত, এবং যদি পারফরম্যান্সের চেয়ে নির্ভুলতা বেশি গুরুত্বপূর্ণ হয় তবে BigDecimal ব্যবহার করতে পারেন। আপনি এছাড়াও জানলেন যে Fixnum অবজেক্টগুলো ইন্টারপ্রেটার লেভেলে বিশেষ, কিন্তু Bignum গুলো সাধারণ অবজেক্ট।
যদি এই পোস্ট আপনার কাছে আকর্ষণীয় লাগে, তাহলে নিচের ফর্ম থেকে আমার নিউজলেটারে সাইন-আপ করতে ভুলবেন না! 🙂