#!/usr/bin/perl
require 5.003;
use strict;

die "Usage: irr_del <data file>\n" if $#ARGV < 0;

my $iters_max   = 20;    # maximum number of iterations
my $epsilon     = 1.0e-6; # jump out of loop if change < $epsilon
my $u           = 0.0;    # initial guess.  interest = exp(-$u) - 1
my(@pos_d, @pos_t, @neg_d, @neg_t, $dollars, $time, $pos, $d_pos, $neg,
   $d_neg, $iters, $delta, $i, $tmp);

while(<>) {
    chomp;
    ($dollars, $time) = split;
    write;
  switch:
    {
push(@pos_d,  $dollars), push(<pos_t, $time), last if $dollars > 0.0;
        push(@neg_d, -$dollars), push(@neg_t, $time), last if $dollars < 0.0;
        die "Cannot have dollar amount = \$0.00 !...\n";
    }
}
die "\nCannot calculate irr. Need income AND expenditures!...\n=" unless
    $#pos_d >= 0 and $#neg_d >= 0;

for($iters = $iters_max; $iters > 0; $iters--) {
    $pos = $d_pos = $neg = $d_neg = 0.0;
    for($i = 0; $i <= $#pos_d; $i++) {
        $pos   += ($tmp = $pos_d[$i] * exp($u * $pos_t[$i]));
        $d_pos += $tmp * $pos_t[$i];
    }
    for($i = 0; $i <= $#neg_d; $i++) {
        $neg   += ($tmp = $neg_d[$i] * exp($u * $neg_t[$i]));
        $d_neg += $tmp * $neg_t[$i];
    }
    $delta = log($neg / $pos) / ($d_neg / $neg - $d_pos / $pos);
    last if abs($delta) < $epsilon; # Newton converged
    $u -= $delta;                   # next guess
}
if($iters > 0) {
    printf
  "\nIRR = %.4f%% (discrete) = %.4f%% (continuous) after %u iteration%s.\n",
          100.0 * (exp(-$u) - 1.0), -100 * $u,
          $iters_max - $iters + 1, $iters_max - $iters == 0 ? '' : 's';
} else {
    print "irr does not converge in $iters_max iterations\n";
}

format STDOUT_TOP =
 Income($)     Time (yr)
 =========     =========
.

format STDOUT = 
@######.##      @##.##
$dollars,       $time
.


