Listing 1. irr.pl

#!/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 "Dollar amount cannot = \$0.00 !...\n";
   }
}
die "\nCan't calculate. Need income AND expenses!\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%% ",
   printf "(continuous) after %u "
   printf "iteration%s.\n",
   100.0 * (exp(-$u) - 1.0), -100 * $u,
   $iters_max - $iters + 1,
   $iters_max - $iters == 0 ? '' : 's';
} else {
   printf "irr doesn't converge in $iters_max",
   printf " iterations\n";
}

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

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