return to first page linux journal archive
keywordscontents

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
.