কম্পিউটার টিউটোরিয়াল

রুবি নম্বর গভীরভাবে: ইন্টিজার, ফ্লোট এবং বিগডেসিমেল ব্যাখ্যা

রুবি ২.৪ সংস্করণে 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 ক্লাস ব্যবহার করুন।

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 চেয়ে ১২ গুণ ধীর, এবং এটাই ডিফল্ট না হওয়ার কারণ।

Fixnum বনাম Bignum

এই সেকশনে, রুবি ২.৪ এর আগে Fixnum এবং Bignum এর পার্থক্য নিয়ে আলোচনা করব।

কিছু কোড দিয়ে শুরু করা যাক:

1.class           # Fixnum
100000000000.class # Bignum

রুবি স্বয়ংক্রিয়ভাবে সঠিক ক্লাস তৈরি করে, এবং প্রয়োজনে Fixnum-কে Bignum-এ প্রোমোট করে দেয়।

নোট: ৬৪-বিট রুবি ইন্টারপ্রিটার থাকলে 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))

এখানে "বিট শিফটিং" (bit shifting) হয়, যা সব বিটকে বাম বা ডানে সরায়। এক পজিশন বামে শিফট করা মানে ২ দিয়ে গুণ করা, এবং এটাই ফর্মুলা (number * 2) + 1 হওয়ার কারণ। +1 আসে FIXNUM_FLAG থেকে।

বিপরীতে, Bignum সাধারণ ক্লাসের মতো কাজ করে এবং সাধারণ অবজেক্ট আইডি ব্যবহার করে:

111111111111111.object_id # 23885808

এটি বোঝায় Fixnum অবজেক্টগুলো ইন্টারপ্রেটার লেভেলে সিম্বলের মতো কাজ করে,حين Bignum অবজেক্টগুলো স্ট্রিং-এর মতো।

রুবি ২.৪-এ Integer

রুবি ২.৪ থেকে Fixnum এবং Bignum ডিপ্রিকেটেড, কিন্তু পেছনে থেকে তারা একইভাবে কাজ করে।

রুবি স্বয়ংক্রিয়ভাবে এক টাইপ থেকে অন্য টাইপে স্যুইচ করে—ক্লাস পরিবর্তন किए বিনা।

এমনつまり ছোট Integer সংখ্যাগুলো এখনও Fixnum এর মতোই অপারেট করে।

সারসংক্ষেপ

এই পোস্টে আপনি রুবির বিভিন্ন নম্বর-সম্পর্কিত ক্লাস সম্পর্কে জানলেন।

আপনি জানলেন যে ফ্লোট অনিশ্চিত, এবং যদি পারফরম্যান্সের চেয়ে নির্ভুলতা বেশি গুরুত্বপূর্ণ হয় তবে BigDecimal ব্যবহার করতে পারেন। আপনি এছাড়াও জানলেন যে Fixnum অবজেক্টগুলো ইন্টারপ্রেটার লেভেলে বিশেষ, কিন্তু Bignum গুলো সাধারণ অবজেক্ট।

যদি এই পোস্ট আপনার কাছে আকর্ষণীয় লাগে, তাহলে নিচের ফর্ম থেকে আমার নিউজলেটারে সাইন-আপ করতে ভুলবেন না! 🙂

  1. রুবি ডিপেন্ডেন্সি ম্যানেজমেন্ট মাস্টারিং: Rbenv, RubyGems, এবং Bundler কীভাবে ইন্টারঅ্যাক্ট করে

  2. AASM দিয়ে রুবিতে স্টেট মেশিন মাস্টার করুন: একটি প্র্যাক্টিক্যাল গাইড

  3. রুবি ২.৬-এ MJIT বুঝতে: কীভাবে জাস্ট-ইন-টাইম কম্পাইলার পারফরম্যান্স বাড়ায়

  4. রুবি অ্যারে 습득: প্র্যাক্টিক্যাল উদাহরণ এবং অপরিহার্য মেথডগুলো