পাঠ ২০ · ৫৭-এর মধ্যে · মডিউল ৫

ইন্টারনাল রেট অফ রিটার্ন (IRR) — ধারণা ও হিসাব

Internal rate of return (IRR) — concept & calculation
১১ মিনিট পড়া মধ্যবর্তী · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • IRR-এর সংজ্ঞা — NPV(i*) = 0 সমীকরণ হিসেবে, এবং এটি কেন একটি "রুট-ফাইন্ডিং" সমস্যা
  • বাইসেকশন পদ্ধতির মূল ধারণা — ইন্টারমিডিয়েট ভ্যালু থিওরেম কীভাবে গ্যারান্টি দেয় একটি রুট আছে
  • Python-এ npv() ও find_irr() ফাংশন লিখে একটি সত্যিকারের বাইসেকশন সমাধান
  • কনভারজেন্স কীভাবে যাচাই করতে হয় — পাওয়া IRR-এ NPV আসলেই শূন্যের কাছাকাছি কি না তা প্রিন্ট করে দেখা

১ · IRR কী — NPV=0 হওয়ার রেট

IRRInternal Rate of Returnসেই একক সুদের হার, যেখানে একটি ক্যাশ ফ্লো সিরিজের নেট প্রেজেন্ট ওয়ার্থ ঠিক শূন্য হয়। হলো এমন একটি সুদের হার $i^*$, যা একটি প্রজেক্টের সব ক্যাশ ফ্লোকে (M2-M3-এর সিঙ্গেল-পেমেন্ট ও সিরিজ ফ্যাক্টর দিয়ে) বছর ০-তে ছাড় দিয়ে যোগ করলে ঠিক শূন্য দেয়:

$$NPV(i^*) = \sum_{t=0}^{n} \frac{CF_t}{(1+i^*)^t} = 0$$

এই সমষ্টিটা M2-M3-এ শেখা একই ধরনের ছাড়যুক্ত ক্যাশ ফ্লো যোগফল — শুধু এখানে $i$ অজানা, আর সমীকরণের মান শূন্যের সমান হতে হবে। $n$ বড় হলে এটি $i$-এর একটি উচ্চ-ডিগ্রির বহুপদী সমীকরণে পরিণত হয়, যার সাধারণত কোনো বন্ধ-আকারের (closed-form) বীজগাণিতিক সমাধান থাকে না — তাই সংখ্যাগত (numerical) পদ্ধতি — যেমন বাইসেকশন বা নিউটন-র‌্যাফসন — ব্যবহার করে আনুমানিক সমাধান বের করতে হয়, যতক্ষণ না তা কাঙ্ক্ষিত নির্ভুলতায় পৌঁছায়।

সংজ্ঞা
$NPV(i^*)=0$ — যে হারে সব ক্যাশ ইনফ্লো ও আউটফ্লো ঠিক ভারসাম্যে আসে।
সিদ্ধান্ত নিয়ম
IRR ≥ MARR হলে গ্রহণযোগ্য, IRR < MARR হলে প্রত্যাখ্যাত — M4-এর PW গ্রহণ-নীতির সমতুল্য।
কীভাবে বের করা হয়
বীজগাণিতিক সমাধান নেই (সাধারণত) — বাইসেকশন বা নিউটন-র‌্যাফসনের মতো সংখ্যাগত রুট-ফাইন্ডিং লাগে।

২ · বাইসেকশন পদ্ধতি — মূল ধারণা

বাইসেকশন পদ্ধতি ইন্টারমিডিয়েট ভ্যালু থিওরেম (Intermediate Value Theorem)-এর উপর ভিত্তি করে কাজ করে: যদি কোনো নিরবচ্ছিন্ন ফাংশন $f$-এর জন্য $f(lo)$ ও $f(hi)$-এর চিহ্ন বিপরীত হয় (একটি ধনাত্মক, একটি ঋণাত্মক), তাহলে $lo$ ও $hi$-এর মাঝে অন্তত একটি রুট (যেখানে $f=0$) অবশ্যই থাকবে। ধাপগুলো —

  • একটি ব্র্যাকেট $[lo, hi]$ বাছাই করো যেখানে $NPV(lo)$ ও $NPV(hi)$-এর চিহ্ন বিপরীত
  • মধ্যবিন্দু $mid = (lo+hi)/2$ বের করে $NPV(mid)$ হিসাব করো
  • $NPV(mid)$-এর চিহ্ন $NPV(lo)$-এর সাথে মিলে গেলে $lo=mid$, নাহলে $hi=mid$ — এভাবে ইন্টারভ্যাল প্রতিবার অর্ধেক হয়
  • ইন্টারভ্যাল যথেষ্ট ছোট (বা $NPV(mid)$ যথেষ্ট শূন্যের কাছে) না হওয়া পর্যন্ত এই ধাপ পুনরাবৃত্তি করো

প্রতি ধাপে ইন্টারভ্যাল ঠিক অর্ধেক হয়ে যায়, তাই এটি নিশ্চিতভাবে (গ্যারান্টিসহ) কাঙ্ক্ষিত নির্ভুলতায় পৌঁছায় — কিন্তু ধীরে ধীরে (প্রতি পুনরাবৃত্তিতে মাত্র এক বিট নির্ভুলতা বাড়ে)। নিচের কোডে এটি একটি বাউন্ডেড for লুপে লেখা হয়েছে, যাতে ভুল করে অসীম লুপে আটকে না যায়।

৩ · Python-এ জেনুইন বাইসেকশন IRR সমাধান

ধরা যাক আজ $10,000 বিনিয়োগ করলে পরের ৪ বছরে যথাক্রমে $3,000, $4,000, $5,000, $3,000 ফেরত আসে। নিচের কোডে npv() ফাংশন M2-M3-এর ছাড়যুক্ত সমষ্টি হিসাব করে, আর find_irr() ফাংশন সেই npv()-কে বার বার ডেকে বাইসেকশন করে IRR বের করে — শেষে পাওয়া IRR-এ NPV আসলেই শূন্যের কাছাকাছি কি না তা প্রিন্ট করে কনভারজেন্স যাচাই করা হয়েছে।

Python
# IRR -- NPV(i*) = 0 হওয়ার হার i* বের করা, জেনুইন বাইসেকশন দিয়ে

def npv(cashflows, i):
    return sum(cf / (1 + i) ** t for t, cf in cashflows)

def find_irr(cashflows, lo=-0.5, hi=1.0, tol=1e-7, max_iter=200):
    f_lo = npv(cashflows, lo)
    f_hi = npv(cashflows, hi)
    if f_lo * f_hi > 0:
        raise ValueError("bracket-এ NPV চিহ্ন বদলাচ্ছে না -- বাইসেকশন সম্ভব নয়")

    for _ in range(max_iter):
        mid = (lo + hi) / 2
        f_mid = npv(cashflows, mid)
        if abs(f_mid) < tol or (hi - lo) / 2 < tol:
            return mid
        if f_lo * f_mid < 0:
            hi = mid
        else:
            lo = mid
            f_lo = f_mid
    return (lo + hi) / 2

# (বছর, ক্যাশ ফ্লো) -- বছর ০-এ $10,000 বিনিয়োগ, তারপর ৪ বছরের রিটার্ন
cashflows = [(0, -10000), (1, 3000), (2, 4000), (3, 5000), (4, 3000)]

irr = find_irr(cashflows)
check_npv = npv(cashflows, irr)

print("ক্যাশ ফ্লো (বছর, পরিমাণ):", cashflows)
print(f"বাইসেকশন দিয়ে বের করা IRR = {irr*100:.4f}%")
print(f"NPV(IRR) = ${check_npv:,.6f}   (শূন্যের কাছাকাছি -- এটাই কনভারজেন্সের প্রমাণ)")

    
লক্ষ্য করুন find_irr()-এ কোনো while True নেই — বরং একটি বাউন্ডেড for _ in range(max_iter) লুপ, যা সর্বোচ্চ ২০০ বার চলার পর নিজে থেকেই থেমে যায়। প্রতি ধাপে ইন্টারভ্যাল অর্ধেক হওয়ায় বাস্তবে tol=1e-7 নির্ভুলতায় পৌঁছাতে মাত্র ৩০-৪০টি ধাপই যথেষ্ট — বাকি ধাপগুলো নিরাপত্তার জন্য একটি সিলিং হিসেবে রাখা হয়েছে।
মূল কথা · Key takeaway

IRR হলো সেই হার যেখানে NPV শূন্য হয়, আর এটি বের করার একমাত্র নির্ভরযোগ্য উপায় সংখ্যাগত রুট-ফাইন্ডিং — বাইসেকশন এর মধ্যে সবচেয়ে সহজ ও নিরাপদ, কারণ এটি প্রতিবার নিশ্চিতভাবে ইন্টারভ্যাল অর্ধেক করে। পরের পাঠে দেখা যাবে সব ক্যাশ ফ্লোর জন্য এই "একটি মাত্র রুট আছে" ধারণা সত্যি নয় — কিছু ক্যাশ ফ্লোতে একাধিক বৈধ IRR থাকতে পারে, যা সিদ্ধান্তকে জটিল করে তোলে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ বাইসেকশন শুরু করার আগে কেন NPV(lo) ও NPV(hi)-এর চিহ্ন বিপরীত হতে হবে?

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

প্র ০২ উপরের উদাহরণে IRR প্রায় কত হলো, এবং এটি বিনিয়োগ সিদ্ধান্তে কীভাবে ব্যবহার হবে?

কোড চালালে IRR প্রায় ১৮% এর কাছাকাছি আসে (হাতে-হিসাব করেও যাচাই করা হয়েছে — সঠিক দশমিক মান কোডই প্রিন্ট করবে)। এই মান একটি কোম্পানির MARR (Minimum Attractive Rate of Return)-এর সাথে তুলনা করা হয় — MARR-এর চেয়ে বেশি হলে প্রজেক্ট আর্থিকভাবে আকর্ষণীয়, কম হলে নয়।

প্র ০৩ tol-এর মান আরও ছোট করলে (যেমন 1e-12) কী হবে?

নির্ভুলতা আরও বাড়বে (IRR আরও বেশি দশমিক ঘর পর্যন্ত সঠিক হবে), কিন্তু বেশি ধাপ লাগবে — কারণ প্রতি ধাপে ইন্টারভ্যাল মাত্র অর্ধেক হয়, তাই আরও ছোট ইন্টারভ্যালে পৌঁছাতে আরও বেশি পুনরাবৃত্তি দরকার। max_iter=200 এখনও যথেষ্ট, কারণ প্রতি ধাপে ইন্টারভ্যাল সূচকীয় হারে (এক্সপোনেনশিয়ালি) ছোট হয়।

অনুশীলন

  1. চিন্তা করুন: একটি প্রজেক্টের IRR যদি কোম্পানির MARR-এর ঠিক সমান হয়, তাহলে সিদ্ধান্ত কী হওয়া উচিত, এবং কেন?

    IRR = MARR মানে $NPV(MARR)=0$ — অর্থাৎ প্রজেক্টটি ঠিক MARR-এর সমান রিটার্ন দেয়, বাড়তি মূল্য (surplus) তৈরি করে না, আবার ক্ষতিও করে না। প্রাথমিক গ্রহণ-নীতি অনুযায়ী এটি "সীমারেখায় গ্রহণযোগ্য" (marginally acceptable), তবে বাস্তবে অন্যান্য গুণগত বিবেচনা (ঝুঁকি, কৌশলগত মূল্য) দিয়ে চূড়ান্ত সিদ্ধান্ত নেওয়া হয়।

  2. পরীক্ষা করুন: উপরের কোড সেলে বছর ৪-এর রিটার্ন 3000-কে 6000-এ বদলে Run চেপে দেখুন IRR কীভাবে বদলায়, এবং NPV(IRR) তারপরও শূন্যের কাছাকাছি থাকে কি না।

    শেষ বছরের রিটার্ন বাড়ানো মানে প্রজেক্ট আরও বেশি মূল্য ফেরত দিচ্ছে, তাই IRR বেড়ে যাবে (আগের চেয়ে বেশি হারে)। find_irr() ফাংশনটি একই থাকবে, শুধু নতুন cashflows দিয়ে আবার বাইসেকশন চালাবে — আর NPV(IRR) এখনও প্রায় শূন্যই থাকবে, কারণ এটি প্রতিটি ক্যাশ ফ্লোর জন্যই সত্যি, শুধু ফলাফলের IRR মানই বদলাবে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ টাইম ভ্যালু অফ মানি, ক্যাশ ফ্লো সিরিজ, ওয়ার্থ-ভিত্তিক তুলনা, রেট অফ রিটার্ন, ডেপ্রিসিয়েশন, ট্যাক্স, ইনফ্লেশন, রিস্ক অ্যানালাইসিস ও ক্যাপিটাল বাজেটিং — সম্পূর্ণ কোর্স এক জায়গায়।
  • Discrete Mathematics কোর্স সহোদর কোর্স সিকোয়েন্স ও সিরিজের সমষ্টির সূত্র — এই পাঠের NPV সমষ্টির গাণিতিক ভিত্তি সেখানেই তৈরি হয়েছে।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Programming Languages & Compiler Design, Software Engineering & Git, Theory of Computation ও Engineering Economics — সব এক জায়গায়।
আগের পাঠ
অসম জীবনকালের অল্টারনেটিভ তুলনা