[net.sources] C Program for Loan Amortization Schedule

dzd@cosivax.UUCP (Dean Douthat) (04/14/84)

In response to a request for software to compute amortization payments and
schedules, the following is submitted. 

                          Tear along dotted line
------------------------------------------------------------------------------
/*
 *  Print amortization schedule for fixed-payment loan on sdtout.
 *
 *  Usage: a.out amount annual term [month year [interval] ]
 *
 *  amount   = principal borrowed ($)
 *  annual   = annual percentage rate of interest (%)
 *  term     = length of loan (years)
 *  month    = month (1-12) loan is made; default = current month
 *  year     = year (00-99) loan is made; default = current year
 *  interval = months between payments (1,2,3,4,6,12); default = 1
 *
 *  The load module should be placed in a file named "amort" and
 *  linked to a file named "amortp". The first will print assuming
 *  continuous form (with form feeds); the second assuming single
 *  sheet feed (with pauses before each page). Actually any names of
 *  five and six characters, respectively will suffice.
 *
 *  Programmed by Dean Douthat
 */
#include <stdio.h>
#include <time.h>
#define EOS '\0'

static int month, year;
static float amount, annual;
static int term, interval, periods, pmts_per_year;
static long int balance, payment, interest;
static double periodic;

main(argc, argv)
int argc;
char *argv[];
{
    int i, line, last, pause;
    double x, r;
    char *malloc();
/*
    Add buffering to stdout in case it is redirected to raw printer output
    that is, usually for a single user system. If output will always be
    spooled, as on a multi-user system, this buffering can usually be omitted.
*/
    setbuf(stdout, malloc(BUFSIZ) );
/*
    Obtain inputs from command line arguments, check validity and supply
    defaults if needed
*/
    if(argc < 4)
    {
        fprintf(stderr,
            "Usage: %s amount annual term [month year [interval] ]\n",
            argv[0]);
        exit(1);
    }
    pause = ( *(argv[0] + 5) != EOS );
    sscanf(argv[1], "%f", &amount);
    if(amount < 0.0) error("Illegal amount");
    sscanf(argv[2], "%f", &annual);
    if(annual < 0.0 || annual > 100.0) error("Illegal annual percentage");
    sscanf(argv[3], "%d", &term);
    if(term <= 0) error("Illegal term");
    if(argc >= 6)
    {
        sscanf(argv[4], "%d", &month);
        if(month < 1 || month > 12) error("Illegal month");
        sscanf(argv[5], "%d", &year);
        if(year < 0 || year > 99) error("Illegal year");
        if(argc >= 7)
        {
            sscanf(argv[6], "%d", &interval);
            if(interval < 1 || interval > 12 || (12 % interval) != 0)
                error("Illegal interval");
        }
        else interval = 1;
    }
    else
    {
        today();
        interval = 1;
    }
/*
    Set initial values
*/
    pmts_per_year = 12/interval;
    periodic = annual/(pmts_per_year * 100.0);
    periods = term * pmts_per_year;
    balance = amount * 100.0;
/*
    Find periodic payment amount
*/
    r = 1.0 + periodic;
    for(x = 1.0, i = 0; i < periods; ++i) x *= r;
    payment = (long) (100.0 * amount * periodic * x/(x - 1.0) + 0.5);
/*
    Compute amortization table values
*/
    for(i = 1; i <= periods; ++i)
    {
        interest = (long) (balance * periodic + 0.5);
        if(last = (i == periods)) payment = interest + balance;
        line = lineout(i, line, last, pause);
    }
}
static long cum, ytd;
static int omonth, oyear;
static char *month_name[] =
{
    "BAD",
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec"
};

lineout(i, line, last, pause)
int i, line, last, pause;
{
    long princ_pay;

    if(line < 4)   /* Starting first page of output */
    {
        omonth = month;
        oyear = year;
        cum = 0.0;
        line = header(pause);
    }
    if( (month += interval) > 12)            /* Just finished a year */
    {
            ytd = 0.0;
            ++year;
            month -= 12;
            if(interval < 12)
            {
                putchar('\n');
                ++line;
            }
            if(line + pmts_per_year > 61) /* Page won't hold another year */
                line = header(pause);          /* Start next page */
    }
    princ_pay = payment - interest;
    balance -= princ_pay;
    cum += interest;
    ytd += interest;
    printf("%5d %s %02d",i,month_name[month],year % 100);
    printf("%12.2f%12.2f%15.2f%15.2f%13.2f\n",princ_pay/100.0,
        interest/100.0, balance/100.0, cum/100.0, ytd/100.0);
    ++line;
    if(last)
    {
        printf("\n   Last Payment = $%.2f",payment/100.0);
        if(!pause) printf("\f\f");
    }
    return(line);
}
static char *type[] =
{
    "BAD",
    "monthly",
    "bimonthly",
    "quarterly",
    "thrice-yearly",
    "BAD",
    "semi-annual",
    "BAD",
    "BAD",
    "BAD",
    "BAD",
    "BAD",
    "annual"
};

header(pause)
int pause;
{
    if(pause)
    {
        fflush(stdout);   /* Can be removed if "setbuf" removed in main */
        fprintf(stderr, "Insert paper; type RETURN when ready ->");
        getchar();
    }
    else putchar('\f');

    printf("\n\n  $%.2f at %2.3f%% annually for %d years starting %s %d\n",
            amount,annual,term,month_name[omonth],oyear);
    printf("  in %d %s payments of $%.2f",periods,type[interval],
            payment/100.0);
    printf("\n\n               ");
    printf("Principal    Interest        Balance        Cum Int      YTD Int");
    putchar('\n');
    return(7);
}
today()
{
    struct tm *localtime(), *now;
    long clock, time();

    clock = time(NULL);
    now = localtime(&clock);
    month = now->tm_mon + 1;
    year = now->tm_year;
    if(month <= 0 || month > 12) month = 0;
    year %= 100;
}
error(s)
char *s;
{
    fprintf(stderr, "%s\n",s);
    exit(2);
}
------------------------------------------------------------------------------
                            Tear along dotted line

Dean Douthat

UUCP:   ...!sb1!mb2c!uofm-cv!cosivax!dzd |  Mail: Zahntron, Inc.
Ma:         (313) 995-9762               |        330 E. Liberty
MCI Mail:   DDOUTHAT 187-3270            |        Suite 3B
TWX/TELEX:  6501873270                   |        Ann Arbor, MI
Answerback: 6501873270 MCI               |                 48104