বাইনারি অ্যাডিশন ও সাবট্রাকশন সার্কিট
এই পাঠে যা শিখবেন
- কীভাবে L09-এর ripple-carry adder সরাসরি L18-এর two's complement বিট-প্যাটার্নের উপর কাজ করে
- $5+(-3)=2$ — সম্পূর্ণ বিট-লেভেল অ্যাডার ট্রেস দিয়ে বাস্তবে গণনা করে যাচাই করা (হাত দিয়ে ফলাফল বসিয়ে নয়)
- $5+5$-এর মতো একটি genuine ওভারফ্লো কেস সনাক্ত করা, L18-এর carry-in/carry-out নিয়ম প্রয়োগ করে
- একটিই হার্ডওয়্যার ইউনিট (adder/subtractor) কীভাবে যোগ ও বিয়োগ — দুটোই চালায়, কোনো অতিরিক্ত সার্কিট ছাড়াই
১ · দুটি পাঠের সংশ্লেষণ
এতদিন L09 আর L18 আলাদা আলাদা পাঠ ছিল — L09 শিখিয়েছিল কীভাবে ফুল অ্যাডারL08 — তিনটি বিট (A, B, Cin) যোগ করে Sum ও Cout দেয়। চেইন করে একটি রিপল ক্যারি অ্যাডার বানানো যায়, আর কীভাবে B-কে ইনভার্ট করে Cin=1 দিলে বিয়োগও করা যায়। L18 শিখিয়েছিল ঋণাত্মক সংখ্যাকে Two's Complement বিট-প্যাটার্নে এনকোড করার নিয়ম। এই পাঠে দুটোকে একসাথে জোড়া দেওয়া হচ্ছে — L18-এর বিট-প্যাটার্নগুলো সরাসরি L09-এর অ্যাডার সার্কিটে ঢুকিয়ে, প্রকৃত সাইনড যোগ-বিয়োগ বাস্তবায়ন করা হবে।
সবচেয়ে গুরুত্বপূর্ণ অন্তর্দৃষ্টিটি হলো — CPU-এর অ্যাডার সার্কিট নিজে "জানে না" সে যোগ করছে না ঋণাত্মক সংখ্যা যোগ করছে। সে শুধু বিট-প্যাটার্নগুলো ফুল-অ্যাডার চেইনের মধ্য দিয়ে পাঠায়। Two's complement এমনভাবে ডিজাইন করা যে এই একই, সরল প্রক্রিয়া স্বয়ংক্রিয়ভাবে সঠিক সাইনড ফলাফল দেয় — কোনো বাড়তি "if সংখ্যাটি ঋণাত্মক হলে..." যুক্তির প্রয়োজন নেই।
২ · ওয়ার্কড উদাহরণ — $5 + (-3) = 2$
4-বিট two's complement ব্যবহার করে —
- $5 \to 0101$
- $-3 \to 1101$ (L18-এর ইনভার্ট+১ নিয়মে: +3=0011, ইনভার্ট=1100, +1=1101)
এই দুটো বিট-প্যাটার্ন সরাসরি L09-এর রিপল ক্যারি অ্যাডারে পাঠালে —
ফলাফল ৫ বিটের (একটি অতিরিক্ত ক্যারি-আউট বিটসহ) — কিন্তু যেহেতু আমরা কঠোরভাবে 4-বিট রেজিস্টারে কাজ করছি, সবচেয়ে
বাম দিকের অতিরিক্ত ক্যারি-আউট বিটটি স্বাভাবিকভাবেই বাতিল (discard) হয়ে যায়, রেখে যায় শুধু 0010 = 2 —
যা ঠিক সঠিক উত্তর ($5-3=2$)। CPU-কে "এটা আসলে বিয়োগ ছিল" এটা আলাদাভাবে বুঝতে হয়নি — একই হার্ডওয়্যার
দুটো two's complement বিট-প্যাটার্ন সঠিকভাবেই প্রসেস করেছে।
৩ · ওভারফ্লো পুনরায় — $5+5$ একটি genuine কেস
এখন এমন একটি কেস দেখা যাক যেখানে দুটো প্রকাশযোগ্য সংখ্যা যোগ করলেও ফলাফল প্রকাশযোগ্য রেঞ্জের বাইরে চলে যায়। 4-বিট two's complement-এর সর্বোচ্চ ধনাত্মক মান হলো $+7$ (0111) — কিন্তু $5+5=10$, যা এই রেঞ্জের বাইরে। L18-এর ওভারফ্লো-নিয়ম (সাইন-বিটে ঢোকা ক্যারি ≠ সাইন-বিট থেকে বের হওয়া ক্যারি) এই কেসে সঠিকভাবে ওভারফ্লো পতাকা তুলবে কিনা — তা নিচের কোড সেলে সরাসরি সার্কিট-সিমুলেশন দিয়ে যাচাই করা হচ্ছে।
# L09 + L18 সংশ্লেষণ -- বিট-লেভেল রিপল ক্যারি অ্যাডার/সাবট্রাক্টর দিয়ে প্রকৃত সাইনড অ্যারিথমেটিক
# (সিমুলেটেড ফুল-অ্যাডার চেইন -- কোনো বাস্তব CPU ইনস্ট্রাকশন বা হার্ডওয়্যার অ্যাক্সেস নয়)
def to_twos_complement(n, bits):
if n >= 0:
return bin(n)[2:].zfill(bits)
positive_bits = to_twos_complement(-n, bits)
inverted = "".join("1" if c == "0" else "0" for c in positive_bits)
return bin((int(inverted, 2) + 1) % (2 ** bits))[2:].zfill(bits)
def from_twos_complement(bits_str):
n = len(bits_str)
value = int(bits_str, 2)
return value - 2 ** n if bits_str[0] == "1" else value
def full_adder(a, b, cin):
"""L08 -- তিন বিট যোগ করে (sum, carry_out) দেয়"""
s = a ^ b ^ cin
cout = (a & b) | (cin & (a ^ b))
return s, cout
def ripple_carry_adder(a_bits, b_bits, cin=0):
"""L09 -- N-টি ফুল অ্যাডার চেইন করে, LSB থেকে MSB পর্যন্ত ক্যারি প্রবাহিত হয়"""
n = len(a_bits)
result = ["0"] * n
carry = cin
carry_into_msb = None
for i in range(n - 1, -1, -1):
if i == 0:
carry_into_msb = carry
a, b = int(a_bits[i]), int(b_bits[i])
s, carry = full_adder(a, b, carry)
result[i] = str(s)
carry_out_of_msb = carry
return "".join(result), carry_into_msb, carry_out_of_msb
def adder_subtractor(a_bits, b_bits, subtract_mode=False):
"""L09 -- subtract_mode=True হলে B ইনভার্ট করে Cin=1 দেয় (two's complement বিয়োগ ট্রিক)"""
if subtract_mode:
b_bits = "".join("1" if c == "0" else "0" for c in b_bits)
cin = 1
else:
cin = 0
return ripple_carry_adder(a_bits, b_bits, cin)
print("=== 5 + (-3), 4-বিট two's complement অ্যাডার দিয়ে ===")
a = to_twos_complement(5, 4)
b = to_twos_complement(-3, 4)
result, cin, cout = ripple_carry_adder(a, b)
print(f"a(5) = {a} b(-3) = {b}")
print(f"অ্যাডার আউটপুট বিট = {result} (top-bit carry_out={cout} বাতিল হয়)")
print(f"দশমিক ব্যাখ্যা = {from_twos_complement(result)}")
assert from_twos_complement(result) == 5 + (-3)
print("cross-check (Python native):", 5 + (-3))
print()
print("=== 5 + 5, ওভারফ্লো কেস যাচাই ===")
a = to_twos_complement(5, 4)
b = to_twos_complement(5, 4)
result, cin, cout = ripple_carry_adder(a, b)
overflow = cin != cout
print(f"a(5) = {a} b(5) = {b}")
print(f"অ্যাডার আউটপুট বিট = {result} carry_in(sign)={cin} carry_out(sign)={cout}")
print(f"ওভারফ্লো ফ্ল্যাগ (L18 নিয়ম) = {overflow}")
print(f"(হার্ডওয়্যারের ভুল দশমিক পাঠ, যদি ওভারফ্লো উপেক্ষা করা হতো: {from_twos_complement(result)}, প্রকৃত যোগফল: {5+5})")
print()
print("=== একই adder_subtractor ইউনিট দিয়ে বিয়োগ: 7 - 3 ===")
a = to_twos_complement(7, 4)
b = to_twos_complement(3, 4)
result, cin, cout = adder_subtractor(a, b, subtract_mode=True)
print(f"7 - 3 => বিট {result} => দশমিক {from_twos_complement(result)}")
assert from_twos_complement(result) == 7 - 3
5 + (-3)-এর জন্য কোনো বিশেষ "বিয়োগ মোড"
চালু করতে হয়নি, শুধু সঠিক two's complement বিট-প্যাটার্ন পাঠালেই ripple_carry_adder সঠিক উত্তর দিয়েছে। দ্বিতীয়ত,
5 + 5-এ carry_in(sign)=1 কিন্তু carry_out(sign)=0 হওয়ায় overflow=True সঠিকভাবে ধরা পড়েছে — অ্যাডার
বিট-প্যাটার্ন সরাসরি পড়লে (ইনভার্ট নিয়মে) ভুল দশমিক মান (-6) বেরিয়ে আসত, তাই ওভারফ্লো ফ্ল্যাগ ছাড়া এই ভুল
ধরা পড়ত না — এটাই প্রমাণ করে কেন হার্ডওয়্যারে ওভারফ্লো ফ্ল্যাগ থাকা আবশ্যক।
একটি একক ripple-carry adder circuit, সামান্য একটি XOR-নিয়ন্ত্রিত bit-inverter ও mode-select ওয়্যার যোগ করলেই, যোগ ও বিয়োগ — দুটোই সঠিকভাবে চালাতে পারে, দুই ধরনের অপারেশনের জন্য দুই ধরনের সার্কিট বানানোর প্রয়োজন নেই। এই সাশ্রয়ী ডিজাইনটাই real ALU (Arithmetic Logic Unit) হার্ডওয়্যারের একটি মূল ভিত্তি (M6-এ বিস্তারিত)।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
উপরের কোডে 5 + (-3) গণনায় top-bit-এর carry_out=1 এসেছে, কিন্তু সেটাকে "বাতিল" করা হলো কেন — এটা কি একটা তথ্য হারানো?
না, কারণ আমরা কঠোরভাবে 4-বিট রেজিস্টারে কাজ করছি এবং ফলাফল ($2$) 4-বিটের রেঞ্জের মধ্যেই পুরোপুরি প্রকাশযোগ্য — এই ক্যারি-আউট শুধু একটি "৫ম বিট" যা 4-বিট two's complement রেজিস্টারে জায়গা পায় না, কিন্তু যেহেতু প্রকৃত গাণিতিক উত্তর রেঞ্জের মধ্যেই আছে, এটি বাতিল করলে কোনো ভুল হয় না। L18-এর ওভারফ্লো-নিয়ম অনুযায়ী, শুধু তখনই সমস্যা হবে যখন carry-in আর carry-out আলাদা হয় (যেমন 5+5 কেসে) — 5+(-3) কেসে তারা একই (উভয়ই 1), তাই কোনো ওভারফ্লো ঘটেনি, ক্যারি-আউট নিরাপদে বাতিলযোগ্য।
প্র ০২ যদি একটি সরল অ্যাডার (সাবট্রাক্টর-লজিক ছাড়া) দিয়ে সরাসরি $7$ ও $-3$ যোগ করা হয়, তাহলে কি "বিয়োগ মোড" চালু করা লাগবে?
না — এটাই এই পাঠের মূল বিন্দু। $-3$ ইতিমধ্যে two's complement বিট-প্যাটার্নে এনকোড করা হয়ে গেছে
(to_twos_complement(-3, 4)), তাই এটাকে সরাসরি সাধারণ অ্যাডারে (ripple_carry_adder,
কোনো subtract_mode ছাড়াই) পাঠালেই সঠিক ফলাফল আসে। "সাবট্রাক্টর মোড" (B ইনভার্ট + Cin=1) শুধু তখনই দরকার
যখন ইনপুট দুটো ধনাত্মক বিট-প্যাটার্ন থাকে এবং আমরা একটিকে আরেকটি থেকে বিয়োগ করতে চাই (যেমন কোড সেলের
শেষ উদাহরণ 7 - 3) — সেখানে B আগে থেকে ঋণাত্মক এনকোড করা ছিল না।
প্র ০৩
উপরের 5 + 5 ওভারফ্লো কেসে অ্যাডার আউটপুট বিট 1010 সরাসরি two's complement হিসেবে পড়লে কী মান পাওয়া যায়, আর সেটা কেন "ভুল"?
1010-কে সরাসরি 4-বিট two's complement হিসেবে পড়লে পাওয়া যায় $1\times(-8)+0\times4+1\times2+0\times1
= -6$। এটা স্পষ্টতই ভুল, কারণ প্রকৃত গাণিতিক যোগফল $5+5=10$, $-6$ নয়। সমস্যাটা হলো $10$ 4-বিট signed
রেঞ্জ $[-8,7]$-এর বাইরে, তাই এটি সেই রেঞ্জের মধ্যে "wrap around" করে একটি সম্পূর্ণ ভুল কিন্তু বৈধ-দেখতে
বিট-প্যাটার্নে পরিণত হয়েছে — এই কারণেই ওভারফ্লো ফ্ল্যাগ (carry_in ≠ carry_out) আলাদাভাবে চেক করা বাধ্যতামূলক;
নইলে হার্ডওয়্যার নীরবে একটি সম্পূর্ণ ভুল উত্তর দিয়ে দিত।
অনুশীলন
-
হাতে-কলমে করুন: 4-বিট two's complement ব্যবহার করে $-4 + (-3)$ বিট-লেভেলে যোগ করুন (উভয় সংখ্যাকে আগে two's complement-এ রূপান্তর করুন), তারপর যাচাই করুন এটি ওভারফ্লো ঘটাচ্ছে কিনা।
$-4 \to 1100$, $-3 \to 1101$। যোগ: $1100+1101 = 1\,1001$, top-bit বাতিল করে $1001$। যাচাই: $1\times(-8)+0+0+1 = -7$ — সঠিক ($-4-3=-7$)। carry_in(sign)=1, carry_out(sign)=1 — উভয়ই সমান, তাই ওভারফ্লো নেই, এবং $-7$ 4-বিট রেঞ্জ $[-8,7]$-এর মধ্যেই আছে, যা সামঞ্জস্যপূর্ণ।
-
চিন্তা করুন: $(-8) + (-1)$ 4-বিট two's complement-এ যোগ করলে কি ওভারফ্লো ঘটবে? আগে অনুমান করুন, তারপর কারণ ব্যাখ্যা করুন।
হ্যাঁ, ওভারফ্লো ঘটবে। $-8+(-1)=-9$, যা 4-বিট signed রেঞ্জ $[-8,7]$-এর বাইরে (সবচেয়ে ঋণাত্মক প্রকাশযোগ্য মান $-8$)। বিট-লেভেলে: $-8\to1000$, $-1\to1111$, যোগ $1000+1111=1\,0111$, top-bit বাতিল করলে $0111=+7$ — একটি স্পষ্টভাবে ভুল, উল্টো-চিহ্নের ফলাফল, যা ঠিক ওভারফ্লোর ক্লাসিক লক্ষণ। carry_in(sign) ও carry_out(sign) চেক করলে তারা আলাদা হবে, ফ্ল্যাগ সঠিকভাবে সমস্যাটি ধরবে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ পরের পাঠে (L20) একই বিট-লেভেল চিন্তা দিয়ে গুণ শেখা হবে — Booth's Algorithm দিয়ে, যা যোগ ও বিয়োগ উভয়ই স্মার্টভাবে ব্যবহার করে।
- পাঠ ১৮ · সাইনড নাম্বার রিপ্রেজেন্টেশন — Two's Complement সরাসরি ভিত্তি এই পাঠের বিট-প্যাটার্নগুলো তৈরির নিয়ম ও ওভারফ্লো-ডিটেকশনের গাণিতিক ভিত্তি সেখানেই বিস্তারিত।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems ও Computer Architecture — সব এক জায়গায়।