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