
use strict;

my ($discount, $months) = @ARGV;

($discount > 0 and $discount < 100 
and $months >= 1
) or die <<USAGE;

Usage:
$0 DISCOUNT MONTHS

Discount is a percentage, like 10
Months is how far in advance one is paying, like 24 for two years

USAGE

BEGIN {
    eval "sub DEBUG(){$ENV{DEBUG}}"
}

my ($lowr,$nextr,$highr) = (0,2.5,5);
my $e = 2.71828182845904523536;
my $D = $discount / 100;
my $M = $months - 1; # 
my $C = ($months) * (1-$D) ;

print "$discount% discount on \$$months is \$$C\n";

sub RtoC($){
    my $r = shift;
    # http://en.wikipedia.org/wiki/Time_value_of_money#Present_value_of_an_annuity
    # PV = A / (e**r - 1)
    # A = 1/12
    # 
    my $P = 1 /($e**($r*(1/12)) - 1);   # value of perpetuity yielding 1 per 1/12 at r
    DEBUG and print "at r = $r, principal $P yields 1/12 per 1/12\n";
    1 +                                 # annuity due
    $P     -                            # perpetuity
    $P * ($e**($r*(-$M/12)))            # discounted perpetuity

};


while (1){
    my $result = RtoC $nextr;
    DEBUG and print "$nextr gave $result, want $C\n";
    last if ($result - $C) ** 2 < 0.0000000000000000001;
    if ($result > $C){
        # result is too high, need higher r
        $lowr = $nextr;
        $nextr += (rand(1) * ($highr - $lowr))
    }else{
        # result is too low, need lower r
        $highr = $nextr;
        $nextr -= (rand(1) * ($highr - $lowr))
    }
};
my $r = ($highr + $lowr) / 2;
print " a $discount% discount for $months payment at a time implies an r of $r\n";

my $Month = 0;
my $C2 = 9876543;
print "
MONTH PRINCIPAL-BEFORE PAYMENT PRINCIPAL-AFTER
";
format amortization=
 @###      @#####.#### (@#.##)     @#####.####
 $Month,   $C,         1,       $C2
.
$~ = 'amortization';
while (1){
    $C2 = $C - 1;
    $C2 < -1/24 and last;
    write;
    $C = $C2 * $e**($r * (1/12));
    $Month++;

};

