This program calculates and displays amortization data for fixed-rate mortgages, accepting principal, term (up to 30 years), and annual interest rate as inputs. It pre-computes all monthly payment breakdowns into a two-dimensional array T(N,3), storing per-payment interest, cumulative interest paid, and remaining principal balance for up to 360 entries. Five report modes are available: single payment detail, single year summary, monthly profile scrolling table, yearly profile scrolling table, and a character-graphics plot of the interest/principal split over the loan term. Column alignment for dollar amounts is handled manually by computing display offsets based on the magnitude of each value, using a cascading series of IF comparisons to set tab positions.
Program Analysis
Program Structure
The program is organized as a main setup sequence with five subroutine modules and a main menu loop. Execution begins at line 10 with GOTO 3500, jumping past all subroutine code to the splash/intro section. Control flow is summarized below:
| Line Range | Purpose |
|---|---|
| 10 | Entry point — jumps to initialization |
| 95–496 | Subroutine: Single Payment Report |
| 499–1090 | Subroutine: Single Year Report |
| 1195–1530 | Subroutine: Monthly Profile (scrolling table) |
| 1595–2020 | Subroutine: Yearly Profile (scrolling table) |
| 2195–2470 | Subroutine: Interest/Principal Plot |
| 3500–3730 | Splash screens and introduction text |
| 3800–4180 | Data entry (principal, years, rate) and preliminary results |
| 4200–4490 | First-payment date entry and amortization table computation loop |
| 4490–4850 | Report menu and dispatch loop |
| 4900–4910 | Program termination (CLEAR, CLS) |
Amortization Table Computation
After all inputs are validated, a DIM T(N,3) statement at line 4020 allocates the full payment table, where N = Y * 12 (number of monthly payments, capped at 360 for a 30-year loan). The loop at lines 4410–4480 runs in FAST mode and fills three columns per payment:
T(X,1)— interest portion of payment XT(X,2)— cumulative interest paid through payment XT(X,3)— remaining principal balance after payment X
The monthly payment amount M is computed using the standard annuity formula at line 4030: M = P*I / (1 - (1+I)^(-N)), where I = A/12 is the monthly rate. The rounded value M1 is used for display, while the unrounded M is used in the amortization loop to avoid accumulating rounding errors over the life of the loan — a deliberate and correct design choice.
Rounding Convention
Throughout the program, monetary values are rounded to two decimal places using the idiom (INT (X*100+.5))/100. This banker-style rounding by half-up addition appears consistently in all five report subroutines and in the main computation. A threshold check, IF T3<.1 THEN LET T3=0 (lines 250, 850) and IF ABS T3<.6 THEN LET T3=0 (lines 1400, 1900), handles floating-point residuals in the final balance, preventing a nearly-zero balance from being displayed as a small non-zero number.
Manual Column Alignment
Because the platform’s PRINT statement does not support right-justified numeric output, the program manually computes a starting column Z1, Z2, or Z3 for each dollar figure by testing its magnitude with a cascade of IF statements. For example, lines 300–330 set Z1 to 5, 6, 7, or 8 depending on whether the interest amount is ≥1000, ≥100, ≥10, or smaller. This shifts the dollar sign leftward by one column for each additional digit, approximating right-alignment within a fixed field.
Report Subroutines
All five reports are implemented as GOSUB targets ending with RETURN, called from the dispatch block at lines 4760–4820. After returning, a PAUSE 40000 at line 4830 holds the display until a key is pressed (a standard long-pause keypress-wait idiom), then FAST is set and the menu redraws.
The two profile reports (monthly at 1200, yearly at 1600) implement paginated output: a counter CT tracks rows printed, and at 19 rows the program hits a STOP statement at lines 1430 or 1930. This is intended to pause output, but it unconditionally halts execution rather than waiting for a keypress and continuing — a functional bug. The CLS and header reprint at lines 1440–1460 and 1940–1960 are unreachable dead code because they follow STOP with no conditional path to reach them.
Interest/Principal Plot
The plot subroutine at lines 2200–2470 draws a character-graphics chart using PLOT commands. A Y-axis label is printed character by character from the string Y$=" DOLLARS" using PRINT AT J,0;Y$(J) in a loop, placing one character per screen row. Axis lines are drawn with PLOT loops. Data points are sampled every 6 payments (STEP 6) and scaled to a 40-unit vertical range proportional to the monthly payment M. Both the interest fraction and the principal fraction are plotted per sample, and labels “P” and “I” are positioned at the midpoints of their respective curves using computed AT coordinates.
Input Validation
All numeric inputs are validated with range checks, and invalid entries restart the relevant input section via GOTO. Notable constraints enforced include:
- Principal must be positive (line
3834) - Term must be 1–30 years (line
3864); a special case at line4015handles a half-year term (Y=.5,N=6), inconsistent with the prompt restrictingY>0as integer - Rate must be in decimal form, between 0 and 1 exclusive (line
3894) - Month inputs must be 1–12; year inputs must fall within the computed loan span
A confirmation step at lines 3910–3930 allows the user to re-enter all data if any value is wrong, by checking whether the input string K$ is empty.
Notable Anomalies
- Line
1230contains a typo: “PLEAE ENTER” instead of “PLEASE ENTER”. - The
STOP-based pagination in the profile routines (lines1430,1930) unconditionally terminates the program rather than pausing; theCLS/reprint code immediately following is dead code. - The variable
Yis reused: it stores the loan term in years during setup, but within the yearly profile subroutineY1is computed as the number of remaining years. IfYwere overwritten this would corrupt data, but the subroutine usesY1as its loop counter, so the loan-term value inYis preserved. - Line
4015testsIF Y=.5 THEN LET N=6to support a six-month loan term, but the input validation at line3864only rejectsY<=0, so fractional year values other than0.5would produce a non-integerNpassed toDIM, likely causing an error.
Content
Source Code
10 GOTO 3500
95 REM SINGLE PAYMENT ROUTINE
100 CLS
110 PRINT " SINGLE PAYMENT MODE"
120 PRINT " ''''''''''''''''''''''''''''''''''''''"
130 PRINT AT 5,1;"ENTER THE DATE OF THE PAYMENT IN WHICH YOU ARE INTERESTED"
140 PRINT AT 11,3;"FIRST THE MONTH (2 DIGITS)"
150 INPUT MN
160 IF MN<1 OR MN>12 THEN GOTO 100
170 PRINT AT 15,3;"AND THE YEAR (4 DIGITS)"
180 INPUT YR
190 LET X=(YR-FY)*12+MN-FM+1
200 IF X<1 OR X>N THEN GOTO 100
210 FAST
220 LET T1=(INT (T(X,1)*100+.5))/100
230 LET T2=(INT (T(X,2)*100+.5))/100
240 LET T3=(INT (T(X,3)*100+.5))/100
250 IF T3<.1 THEN LET T3=0
260 LET MP=M1-T1
270 LET MP=(INT (MP*100+.5))/100
280 LET TP=OP-T3+T2
290 LET TP=(INT (TP*100+.5))/100
300 LET Z1=5
310 IF T1<1000 THEN LET Z1=6
320 IF T1<100 THEN LET Z1=7
330 IF T1<10 THEN LET Z1=8
340 LET Z2=5
350 IF MP<1000 THEN LET Z2=6
360 IF MP<100 THEN LET Z2=7
370 IF MP<10 THEN LET Z2=8
380 LET Z3=5
390 IF M1<1000 THEN LET Z3=6
400 IF M1<100 THEN LET Z3=7
410 CLS
420 PRINT "MORTGAGE DATA FOR ";MN;"/";YR
430 PRINT AT 4,4;"PAYMENT:"
440 PRINT AT 6,Z1;"$";T1;TAB 13;" INTEREST"
450 PRINT AT 7,Z2;"$";MP;TAB 13;" PRINCIPAL"
460 PRINT AT 8,5;"................"
470 PRINT AT 9,Z3;"$";M1;TAB 13;" TOTAL"
475 PRINT AT 12,0;"AFTER THIS PAYMENT:"
480 PRINT AT 14,2;"PRINCIPAL BALANCE = $";T3
490 PRINT AT 16,2;"INTEREST PAID = $";T2
494 PRINT AT 18,2;"TOTAL PAID = $";TP
496 RETURN
499 REM SINGLE YEAR ROUTINE
500 CLS
510 LET YI=0
520 PRINT " SINGLE YEAR MODE"
530 PRINT " ''''''''''''''''''''''''''''''''"
540 PRINT AT 8,3;"ENTER THE YEAR IN WHICH YOU ARE INTERESTED (4 DIGITS)"
560 INPUT YR
570 LET LY=FY+Y
580 IF YR<FY OR YR>LY THEN GOTO 500
590 FAST
600 IF YR<>FY THEN GOTO 640
610 LET Z=1
620 LET W=13-FM
630 GOTO 680
640 LET Z=(YR-FY)*12+2-FM
650 LET W=Z+11
660 IF W<N THEN GOTO 680
670 LET W=N
680 FOR X=Z TO W
690 LET YI=YI+T(X,1)
700 NEXT X
710 LET YI=(INT (YI*100+.5))/100
720 IF W<>N AND YR<>FY THEN GOTO 780
730 IF YR=FY THEN GOTO 760
740 LET YP=M1*LM-YI
750 GOTO 790
760 LET YP=M1*(13-FM)-YI
770 GOTO 790
780 LET YP=M1*12-YI
790 LET TPY=YI+YP
800 LET YP=(INT (YP*100+.5))/100
810 LET TP=OP-T(W,3)+T(W,2)
820 LET TP=(INT (TP*100+.5))/100
830 LET T2=(INT (T(W,2)*100+.5))/100
840 LET T3=(INT (T(W,3)*100+.5))/100
850 IF T3<.1 THEN LET T3=0
860 LET Z1=5
870 IF YI<10000 THEN LET Z1=6
880 IF YI<1000 THEN LET Z1=7
890 IF YI<100 THEN LET Z1=8
900 LET Z2=5
910 IF YP<10000 THEN LET Z2=6
920 IF YP<1000 THEN LET Z2=7
930 IF YP<100 THEN LET Z2=8
935 IF YP<10 THEN LET Z2=9
940 LET Z3=5
950 IF TPY<10000 THEN LET Z3=6
960 IF TPY<1000 THEN LET Z3=7
970 IF TPY<100 THEN LET Z3=8
980 CLS
990 PRINT "MORTGAGE DATA FOR YEAR ";YR
1000 PRINT AT 4,4;"TOTALS FOR THE YEAR:"
1010 PRINT AT 6,Z1;"$";YI;TAB 17;"INTEREST"
1020 PRINT AT 7,Z2;"$";YP;TAB 17;"PRINCIPAL"
1030 PRINT AT 8,5;"...................."
1040 PRINT AT 9,Z3;"$";TPY;TAB 17;"TOTAL"
1050 PRINT AT 12,0;"AT YEAR END:"
1060 PRINT AT 14,2;"PRINCIPAL BALANCE = $";T3
1070 PRINT AT 16,2;"INTEREST PAID = $";T2
1080 PRINT AT 18,2;"TOTAL PAID = $";TP
1090 RETURN
1195 REM MONTHLY PROFILE ROUTINE
1200 CLS
1210 PRINT " MONTHLY PROFILE MODE"
1220 PRINT " ''''''''''''''''''''''''''''''''''''''''"
1230 PRINT AT 6,2;"PLEAE ENTER THE DATE AT WHICH THE REPORT SHOULD START"
1240 PRINT AT 12,4;"FIRST THE MONTH (2 DIGITS)"
1250 INPUT MN
1260 IF MN<1 OR MN>12 THEN GOTO 1200
1270 PRINT AT 17,4;"NOW THE YEAR (4 DIGITS)"
1280 INPUT YR
1290 LET Z=(YR-FY)*12+MN-FM+1
1300 IF Z<1 OR Z>N THEN GOTO 1200
1310 FAST
1320 CLS
1330 PRINT "DATE INT TOTAL INT PRIN BAL"
1340 LET CT=0
1350 FOR X=Z TO N
1360 LET T1=(INT (T(X,1)*100+.5))/100
1370 LET T2=(INT (T(X,2)*100+.5))/100
1380 LET T3=(INT (T(X,3)*100+.5))/100
1390 LET CT=CT+1
1400 IF ABS T3<.6 THEN LET T3=0
1410 PRINT " ";MN;TAB 5;T1;TAB 13;T2;TAB 24;T3
1415 IF T3=0 THEN GOTO 1530
1420 IF CT<19 THEN GOTO 1470
1430 STOP
1440 CLS
1450 PRINT "DATE INT TOTAL INT PRIN BAL"
1460 LET CT=0
1470 LET MN=MN+1
1480 IF MN<=12 THEN GOTO 1520
1490 LET MN=1
1500 LET YR=YR+1
1510 PRINT YR
1520 NEXT X
1530 RETURN
1595 REM YEARLY PROFILE ROUTINE
1600 CLS
1610 LET CT=0
1620 LET YI=0
1630 PRINT " PROFILE BY YEAR MODE"
1640 PRINT " ''''''''''''''''''''''''''''''''''''''''"
1650 PRINT AT 8,2;"PLEASE ENTER THE YEAR AT WHICH THE REPORT SHOULD START"
1660 INPUT YR
1670 LET LY=FY+Y
1680 IF YR<FY OR YR>LY THEN GOTO 1600
1690 FAST
1700 IF YR<>FY THEN GOTO 1740
1710 LET Z=1
1720 LET W=13-FM
1730 GOTO 1760
1740 LET Z=(YR-FY)*12+2-FM
1750 LET W=Z+11
1760 LET Y1=FY+Y+1-YR
1770 IF W>N THEN LET W=N
1780 CLS
1790 PRINT "YEAR INT TOTAL INT PRIN BAL"
1800 FOR I=1 TO Y1
1810 LET YI=0
1820 FOR X=Z TO W
1830 LET YI=YI+T(X,1)
1840 NEXT X
1850 LET Y2=YR+I-1
1860 LET YI=(INT (YI*100+.5))/100
1870 LET T2=(INT (T(W,2)*100+.5))/100
1880 LET T3=(INT (T(W,3)*100+.5))/100
1890 LET CT=CT+1
1900 IF ABS T3<.6 THEN LET T3=0
1910 PRINT Y2;TAB 5;YI;TAB 14;T2;TAB 24;T3
1915 IF T3=0 THEN GOTO 2020
1920 IF CT<19 THEN GOTO 1970
1930 STOP
1940 CLS
1950 LET CT=0
1960 PRINT "YEAR INT TOTAL INT PRIN BAL"
1970 LET Z=X
1980 LET W=Z+11
1990 IF W<N THEN GOTO 2010
2000 LET W=N
2010 NEXT I
2020 RETURN
2195 REM P/I PLOT ROUTINE
2200 CLS
2210 FAST
2220 LET Y$=" DOLLARS"
2230 FOR J=1 TO 12
2240 PRINT AT J,0;Y$(J)
2250 NEXT J
2260 FOR J=3 TO 43
2270 PLOT 3,J
2280 NEXT J
2290 FOR J=3 TO 63
2300 PLOT J,3
2310 NEXT J
2320 SLOW
2330 PRINT AT 21,12;"YEARS"
2340 PRINT AT 21,1;"0";TAB 30;"30"
2350 LET C=3
2360 FOR J=1 TO N STEP 6
2370 LET C=C+1
2380 PLOT C,T(J,1)*40/M+3
2390 PLOT C,(M-T(J,1))*40/M+3
2400 NEXT J
2410 LET J=J-1
2420 LET AB=(T(J,1)*40/M+3)/2
2430 LET AC=((M-T(J,1))*40/M+3)/2
2440 PRINT AT AB-1,(C/2)-2;"P"
2450 PRINT AT AC-2,(C/2)-2;"I"
2470 RETURN
3500 SLOW
3510 PRINT AT 11,2;"A T.J. SOFTWARE PRODUCTION"
3520 PAUSE 200
3530 CLS
3540 PRINT AT 11,6;"ALL RIGHTS RESERVED"
3550 PAUSE 200
3560 CLS
3565 PRINT AT 0,10;"INTRODUCTION"
3566 PRINT AT 1,10;"''''''''''''''''''''''''"
3570 PRINT AT 3,3;"THIS PROGRAM WILL ENABLE YOU"
3580 PRINT "TO INVESTIGATE THE DETAILS OF A"
3590 PRINT "FIXED RATE MORTGAGE. TO USE THIS"
3600 PRINT "PROGRAM YOU WILL NEED TO KNOW,"
3610 PRINT "THE AMOUNT YOU WISH TO BORROW OR"
3620 PRINT "THE PRINCIPAL, THE NUMBER OF "
3630 PRINT "YEARS YOU NEED TO PAY IT BACK,"
3640 PRINT "THE INTEREST RATE THE BANK WILL"
3650 PRINT "CHARGE YOU AND THE DATE OF YOUR"
3660 PRINT "FIRST PAYMENT."
3670 PRINT
3680 PRINT " THERE ARE FIVE DIFFERENT"
3690 PRINT "REPORTS AVAILABLE, AFTER VIEWING"
3700 PRINT "A REPORT PRESS ENTER TO RETURN"
3710 PRINT "TO REPORT MENU."
3720 PRINT AT 21,0;"PRESS ENTER TO CONTINUE"
3730 PAUSE 4000
3800 SLOW
3810 CLS
3814 PRINT " DATA ENTRY"
3815 PRINT " ''''''''''''''''''''"
3816 CLEAR
3820 PRINT AT 4,2;"PLEASE ENTER THE PRINCIPAL"
3830 INPUT P
3834 IF P<=0 THEN GOTO 3810
3840 PRINT AT 6,11;"$";P
3850 PRINT AT 9,2;"NOW ENTER THE NUMBER OF YEARS"
3860 INPUT Y
3864 IF Y<=0 OR Y>30 THEN GOTO 3810
3870 PRINT AT 11,11;Y;" YEARS"
3880 PRINT AT 14,2;"AND THE RATE IN DECIMAL FORM"
3890 INPUT A
3894 IF A<=0 OR A>1 THEN GOTO 3810
3900 PRINT AT 16,11;A*100;" PERCENT"
3910 PRINT AT 19,0;" IF ALL DATA IS CORRECT PRESS ENTER. OTHERWISE PRESS ANY CHARACTER AND ENTER."
3920 INPUT K$
3930 IF K$<>"" THEN GOTO 3800
3940 LET OP=P
3950 CLS
4000 LET I=A/12
4010 LET N=Y*12
4015 IF Y=.5 THEN LET N=6
4020 DIM T(N,3)
4030 LET M=P*I/(1-((1+I)**(-N)))
4040 LET M1=(INT (M*100+.5))/100
4050 LET TPD=(INT (M*N*100+.5))/100
4060 CLS
4064 PRINT " BASIC RESULTS"
4065 PRINT " ''''''''''''''''''''''''''"
4070 PRINT "$";P;" FOR ";Y;" YEARS AT ";A
4080 PRINT "$";M1;" MONTHLY"
4090 PRINT "$";TPD;" TOTAL"
4100 LET S=0
4110 LET ST=0
4120 PRINT AT 11,4;"SELECT OPTION CODE"
4130 PRINT AT 13,6;"CODE DESCRIPTION"
4140 PRINT AT 15,8;"1 NEW DATA"
4150 PRINT AT 16,8;"2 CONTINUE"
4155 PRINT AT 17,8;"3 END"
4160 INPUT C1
4164 LET C1=INT C1
4165 IF C1<1 OR C1>3 THEN GOTO 4060
4170 IF C1=1 THEN GOTO 3800
4180 IF C1=3 THEN GOTO 4900
4200 CLS
4205 PRINT " DATE DATA"
4206 PRINT " ''''''''''''''''''"
4210 PRINT AT 3,2;"PLEASE ENTER THE DATE OF THE FIRST PAYMENT"
4220 PRINT AT 8,2;"FIRST THE MONTH (2 DIGITS)"
4230 INPUT FM
4235 IF FM<=0 OR FM>12 THEN GOTO 4200
4240 PRINT AT 12,2;"NOW THE YEAR (4 DIGITS)"
4250 INPUT FY
4255 IF FY<=0 THEN GOTO 4200
4260 PRINT AT 18,4;"FIRST PAYMENT ";FM;"/";FY
4270 LET LM=FM-1
4280 IF LM<>0 THEN GOTO 4300
4290 LET LM=12
4300 PAUSE 200
4400 FAST
4410 FOR X=1 TO N
4420 LET S=I*P
4430 LET T(X,1)=S
4440 LET ST=ST+S
4450 LET T(X,2)=ST
4460 LET P=P-M+S
4470 LET T(X,3)=P
4480 NEXT X
4490 CLS
4500 SLOW
4600 PRINT " BASIC RESULTS"
4605 PRINT " ''''''''''''''''''''''''''"
4608 PRINT "$";OP;" FOR ";Y;" YEARS AT ";A
4610 PRINT "$";M1;" MONTHLY"
4620 PRINT "$";TPD;" TOTAL"
4625 PRINT AT 8,7;"REPORT MENU"
4626 PRINT AT 9,7;"''''''''''''''''''''''"
4630 PRINT AT 10,4;"SELECT REPORT CODE:"
4640 PRINT AT 12,4;"CODE DESCRIPTION"
4660 PRINT
4670 PRINT TAB 5;"1 SINGLE PAYMENT DATA"
4680 PRINT TAB 5;"2 SINGLE YEAR DATA"
4690 PRINT TAB 5;"3 PROFILE BY MONTH"
4700 PRINT TAB 5;"4 PROFILE BY YEAR"
4710 PRINT TAB 5;"5 INT/PRIN PLOT"
4720 PRINT TAB 5;"6 NEW DATA"
4730 PRINT TAB 5;"7 END"
4735 SLOW
4740 INPUT C2
4750 IF C2<1 OR C2>7 THEN GOTO 4840
4760 IF C2=1 THEN GOSUB 100
4770 IF C2=2 THEN GOSUB 500
4780 IF C2=3 THEN GOSUB 1200
4790 IF C2=4 THEN GOSUB 1600
4800 IF C2=5 THEN GOSUB 2200
4810 IF C2=6 THEN GOTO 3800
4820 IF C2=7 THEN GOTO 4900
4830 PAUSE 40000
4835 FAST
4840 CLS
4850 GOTO 4600
4900 CLEAR
4910 CLS
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

