Internal Rate of Return (IRR)

The internal rate of return is the discount rate for an investment that makes the net present value of the investment (the discounted stream of revenue, less the initial investment) equal to zero. For a constant revenue in each time period, and assuming revenues start in time period one, it is the value where

Investment = Revenue per Time Period * [1/(1+r) + 1/(1+r)^2 + ... 1/(1+r)^T]

The sum can be done explicitly, to give

Investment = Revenue per Time Period * [(1+r)^T) - 1]/[r * (1+r)^T]

The problem is to solve for r. It turns out to be reasonably quick to solve it using Newton's method after changing variables to

z = (1+r)^T

The proc below does this calculation with the input variables

  • inv: Initial investment
  • rev: Revenue per time period
  • nper: Number of time periods (T in above equations)
#*******************************************
#
#   Solve the equation for r:
#      
#      inv = rev * ((1 + r)^nper - 1)/(r*(1 + r)^nper)
#   
#   Solve using Newton's method in terms of z, where
#     z = (1 + r)^nper
#
#********************************************


proc irr {inv rev nper} {
    
    set r [expr {double($rev)/double($inv)}]
    if {$r * $nper < 1} {
        set r -0.5
    }
    set z [expr {pow(1.0 + $r, $nper)}]
    set invnper [expr {1.0/double($nper)}]
    set gprime $rev
    
    set n 0
    while {1} {
        set f [expr {$inv * $r * $z}]
        set g [expr {$rev * ($z - 1.0)}]
        set fprime [expr {$inv * ($r + (1.0 + $r) * $invnper)}]
        set znext [expr {$z - ($f - $g)/($fprime - $gprime)}]
        if {$znext <= 0.0} {
            set r -1.0
            break
        }
        set rnext [expr {pow($znext, $invnper) - 1.0}]
        puts "$r\t[expr {abs($r - $rnext)}]"
        if {abs($r - $rnext) < 1.e-7} {
            break
        }
        set z $znext
        set r $rnext
        incr n
    }
    puts "n: $n"
    return $r
}