অধ্যায় 05

সংখ্যা নিয়ে হিসাব — ভাগ, ভাগশেষ আর দশমিকের ফাঁদ

সাতটি গাণিতিক অপারেটর, কোনটি আগে চলে, পূর্ণ ভাগ ও ভাগশেষ কোথায় কাজে লাগে, আর দশমিক সংখ্যা কেন মাঝে মাঝে অদ্ভুত উত্তর দেয়।

30 মিনিটPython 3.12
  1. 1সমস্যা
  2. 2বোঝা
  3. 3উদাহরণ
  4. 4অনুমান
  5. 5নিজে করা
  6. 6কঠিন করা

যে সমস্যাটা আমরা সমাধান করছি

১৭টি বই আছে, এক বাক্সে ৫টা ধরে। কত বাক্স লাগবে, আর কয়টা বই বাইরে পড়ে থাকবে?

এই প্রশ্নের উত্তর 17 / 5 নয়। ওটা দেয় 3.4, আর ৩.৪টা বাক্স বলে কোনো জিনিস নেই। আপনার দরকার দুটো আলাদা উত্তর: কতগুলো পুরো আর কতটা বাকি। পাইথনে দুটোরই আলাদা অপারেটর আছে, আর এই দুটোই সবচেয়ে বেশি কাজে লাগে — পেজিনেশন, সময়কে ঘণ্টা-মিনিটে ভাগ করা, জোড়-বিজোড় বের করা, সবই এখান থেকে।

সাথে আরেকটা জিনিস যা প্রথমবার দেখলে সবাই থমকে যায়: পাইথনে 0.1 + 0.2 লিখলে উত্তর 0.3 আসে না। কেন আসে না, আর এটা নিয়ে কী করতে হয়, সেটাও আজ জেনে যাবেন।

এই মিশন শেষে আপনি পারবেন

  • সাতটি গাণিতিক অপারেটর ব্যবহার করতে
  • বলতে কোন হিসাব আগে চলে, আর বন্ধনী কখন লাগে
  • // আর % কোথায় ব্যবহার করতে হয় তা চিনতে
  • বুঝতে কেন / সব সময় দশমিক দেয়, এমনকি ভাগ মিলে গেলেও
  • দশমিক সংখ্যার নির্ভুলতার সীমাটা মাথায় রেখে হিসাব লিখতে

আগে যা জানা লাগবে: ভেরিয়েবল আর টাইপ।


সাতটি অপারেটর

python
print(10 + 3)
print(10 - 3)
print(10 * 3)
print(10 / 3)
print(10 // 3)
print(10 % 3)
print(10 ** 3)
text
13
7
30
3.3333333333333335
3
1
1000

শেষ তিনটি একটু ব্যাখ্যা চায়:

  • // — পূর্ণ ভাগ। ভাগ করে দশমিকের আগের অংশটা রাখে, বাকিটা ফেলে দেয়
  • % — ভাগশেষ। ভাগ করার পর কত পড়ে থাকল
  • ** — ঘাত। 10 ** 3 মানে ১০-এর ঘন
/ সব সময় দশমিক দেয়। 10 / 5 লিখলেও উত্তর আসে 2.0, 2 নয়। ভাগ মিলে গেছে কি না তার উপর টাইপ নির্ভর করলে প্রোগ্রামের আচরণ অনিশ্চিত হয়ে যেত, তাই পাইথন এখানে একটাই নিয়ম রাখে — / মানেই float। পূর্ণসংখ্যা দরকার হলে // ব্যবহার করুন।

বাক্সের সমস্যাটার সমাধান

python
books = 17
per_box = 5

full_boxes = books // per_box
left_over = books % per_box

print("Full boxes:", full_boxes)
print("Left over :", left_over)
text
Full boxes: 3
Left over : 2

তিন বাক্স ভরে যাবে, আর ২টা বই বাইরে থাকবে। // আর % জোড়ায় জোড়ায় আসে — একটা বলে "কতগুলো পুরো", আরেকটা বলে "কতটা বাকি"।

এই একই জোড়া আরও অনেক জায়গায়:

python
total_seconds = 500

minutes = total_seconds // 60
seconds = total_seconds % 60

print(minutes, "min", seconds, "sec")
text
8 min 20 sec

আর % দিয়ে জোড়-বিজোড় বের করা যায়। যেকোনো সংখ্যাকে ২ দিয়ে ভাগ করলে ভাগশেষ হয় 0 (জোড়) বা 1 (বিজোড়):

python
print(14 % 2)
print(15 % 2)
text
0
1

শর্ত নিয়ে মিশনে এই ভাগশেষটাই কাজে লাগবে।

কোন হিসাব আগে চলে

পাইথন গণিতের সেই পুরনো ক্রমই মানে — গুণ-ভাগ আগে, যোগ-বিয়োগ পরে:

python
print(10 + 5 * 2)
print((10 + 5) * 2)
text
20
30

প্রথম লাইনে 5 * 2 আগে হয়েছে, তারপর ১০ যোগ হয়েছে। দ্বিতীয় লাইনে বন্ধনী ক্রমটা বদলে দিয়েছে।

ক্রমটা উপর থেকে নিচে:

  1. **
  2. *, /, //, %
  3. +, -
python
print(2 + 3 * 4 ** 2)
text
50

4 ** 2 হলো 16, তারপর 3 * 16 হলো 48, তারপর 2 + 48 হলো 50।

সন্দেহ হলে বন্ধনী দিন। নিয়ম মুখস্থ থাকলেও (a + b) / 2 লেখা a + b / 2 লেখার চেয়ে ভালো — কারণ পরের বার যে পড়বে, তাকে আর নিয়ম মনে করতে হবে না। বাড়তি বন্ধনী কোডকে ধীর করে না, শুধু পরিষ্কার করে।

এই একটা ভুল নতুনদের সবচেয়ে বেশি হয় — গড় বের করার সময়:

python
a = 10
b = 20
c = 30

wrong = a + b + c / 3
right = (a + b + c) / 3

print("Wrong:", wrong)
print("Right:", right)
text
Wrong: 40.0
Right: 20.0

প্রোগ্রামটা কোনো ত্রুটি দেয়নি। কোনো লাল লেখা নেই, কিছুই ভাঙেনি — শুধু উত্তরটা ভুল। এটাই সবচেয়ে বিপজ্জনক ধরনের বাগ, কারণ পাইথন আপনাকে সাবধান করবে না। শুধু আপনি নিজে হিসাব মিলিয়ে দেখলেই ধরা পড়বে।

দশমিকের ফাঁদ

python
print(0.1 + 0.2)
text
0.30000000000000004

এটা পাইথনের দোষ নয়। কম্পিউটার সংখ্যা রাখে দুই ভিত্তিতে (বাইনারিতে), আর 0.1-কে বাইনারিতে হুবহু লেখা যায় না — ঠিক যেমন ১/৩ কে দশমিকে হুবহু লেখা যায় না, 0.3333... চলতেই থাকে। তাই কম্পিউটার খুব কাছাকাছি একটা মান রাখে, আর যোগ করলে সেই সামান্য পার্থক্যটা চোখে পড়ে যায়। জাভাস্ক্রিপ্ট, জাভা, সি — সবখানে একই আচরণ।

দুটো ব্যবহারিক পরিণতি:

এক — দেখানোর সময় round() ব্যবহার করুন:

python
total = 0.1 + 0.2
print(round(total, 2))
text
0.3

round(total, 2) মানে দশমিকের পর দুই ঘর পর্যন্ত রাখো।

দুই — দুটো দশমিক সংখ্যা == দিয়ে মেলাতে যাবেন না:

python
print(0.1 + 0.2 == 0.3)
text
False

এটি সেই ফাঁদ যা আর্থিক হিসাবে ভুল ধরায়। বড় প্রজেক্টে অর্থের হিসাব float-এ রাখা হয় না — সবচেয়ে ছোট এককটিকে পূর্ণসংখ্যা হিসেবে রাখা হয় (৪৯.৯৯ মানে 4999), অথবা decimal নামের আলাদা একটা মডিউল ব্যবহার করা হয়। এখন শুধু জেনে রাখুন সীমাটা কোথায়; মডিউল আসবে পরে।


একটা সম্পূর্ণ উদাহরণ

packing.py:

python
# Work out packing and shipping for one order
total_items = 47
items_per_box = 6
box_cost = 35.5

full_boxes = total_items // items_per_box
loose_items = total_items % items_per_box

# A partly filled box still costs a full box
boxes_needed = full_boxes
if loose_items > 0:
    boxes_needed = full_boxes + 1

shipping = boxes_needed * box_cost

print("Items        :", total_items)
print("Full boxes   :", full_boxes)
print("Loose items  :", loose_items)
print("Boxes needed :", boxes_needed)
print("Shipping     :", round(shipping, 2))
text
Items        : 47
Full boxes   : 7
Loose items  : 5
Boxes needed : 8
Shipping     : 284.0

if লাইনটা এখনো শেখানো হয়নি — পরের কয়েকটা মিশনে সেটাই আসছে। এখন শুধু পড়ে বোঝার চেষ্টা করুন: বাইরে কিছু বই পড়ে থাকলে একটা বাড়তি বাক্স লাগে।


কিছু ভাঙা অবস্থা ও তার সমাধান

ZeroDivisionError: division by zero শূন্য দিয়ে ভাগ করা হয়েছে। গণিতেও এটা অসংজ্ঞায়িত, তাই পাইথন থেমে যায়। ভাগ করার আগে ভাজকটা শূন্য কি না দেখে নিতে হয় — শর্ত শেখার পর সেটা সহজ হবে।

10 / 5 দিয়েছে 2.0, কিন্তু আমার 2 দরকার // ব্যবহার করুন, অথবা int(10 / 5) লিখুন। প্রথমটাই ভালো — উদ্দেশ্যটা কোড পড়েই বোঝা যায়।

ঋণাত্মক সংখ্যায় // অন্যরকম উত্তর দিচ্ছে -7 // 2 দেয় -4, -3 নয়। পাইথন নিচের দিকে কাটে, শূন্যের দিকে নয়। ঋণাত্মক সংখ্যা নিয়ে কাজ করলে এটা মনে রাখতে হবে।

হিসাব ঠিক লাগছে কিন্তু উত্তর ভুল বন্ধনী গুনে দেখুন, আর প্রতিটা ধাপ আলাদা লাইনে ভেঙে ছেপে দেখুন। ভুলটা প্রায় সব সময় অপারেটরের ক্রমে।

দশমিকের পর অনেক লম্বা সংখ্যা আসছে এটা ত্রুটি নয়, দশমিক সংখ্যার স্বাভাবিক আচরণ। দেখানোর সময় round() দিয়ে ছোট করে নিন।