This listing contains two separate mortgage-related financial programs. The first, “MORTGAGE PAYMENT ANALYSIS,” calculates amortisation schedules for a loan given principal, number of periods, and annual interest rate, printing each period’s payment breakdown to screen and optionally to a printer via LPRINT. The second, “PREPAYMENT,” shows the effect of making extra monthly payments on a mortgage, displaying a table of years remaining, effective interest rate, extra payment per month, and total dollars saved compared to the original repayment schedule. Both programs use a 32-character DIM’d string as a right-justification spacer for formatted numeric output, and both support optional hard-copy output. The amortisation formula uses the standard present-value annuity calculation, with rounding applied via the INT(x*100+0.05)/100 pattern to two decimal places.
Program Analysis
The listing contains two entirely independent BASIC programs saved back-to-back. The first (lines 10–9999) is a period-by-period amortisation schedule generator named MORTGAGE ANALYSI S. The second (lines 10–9999, restarting) is a prepayment-savings calculator named PREPAYMENT. Both share structural idioms but differ in purpose.
Program 1 – Mortgage Payment Analysis
Program Structure
- Lines 10–30: Initialise counter
C, dimension spacer stringC$, enter SLOW mode. - Line 100: Title banner in inverse video.
- Lines 1000–1130: User input phase — principal
P, periodsL, annual rateR, hard-copy flagY$, starting periodWP. - Line 1900: Switch to FAST mode for calculation.
- Lines 2000–2070: Compute monthly payment
Musing the annuity formula. - Lines 2090–2320: Main amortisation loop over
Nfrom 1 toL. - Lines 3000–3220: GOSUB for LPRINT hard-copy output of one period’s data.
- Lines 3500–3550: GOSUB to format a number string to exactly two decimal places.
Annuity Calculation
The monthly payment is derived by the standard present-value annuity formula. The monthly interest rate is I = R/1200. The compound factor T is built iteratively in a loop rather than using a power function (which is unavailable as a single operator):
- Lines 2020–2040:
T = (1+I)^Lcomputed by repeated multiplication. - Line 2050:
T = 1 - 1/T, giving the annuity denominator. - Line 2060:
M = P*I/T. - Line 2070: Rounds
Mto two decimal places usingINT(M*100+0.05)/100.
Screen vs. Printer Output
The main loop at line 2185 skips screen output for periods before WP or when hard copy is requested (Y$="Y"). The GOSUB at line 2310 handles printer output and itself returns immediately unless both conditions are met (line 3000). This means screen and printer output are mutually exclusive by design — if Y$="Y", no screen display of individual periods occurs.
String Right-Justification
The 32-character string C$ (initialised by DIM to all spaces) is sliced with C$( TO 18-LEN STR$ N) to pad labels and values to a fixed column width for LPRINT output. This is a compact ZX81 idiom that avoids explicit space-printing loops.
Decimal Formatting Subroutine (Lines 3500–3550)
The subroutine at 3500 ensures a number always prints with exactly two decimal places:
- Re-rounds to two places via
INT(100*PP+0.05)/100. - If the result is a whole number (no decimal part), appends
".00". - If there is only one decimal digit, appends
"0".
Note that the test at line 3530 uses VAL P$=INT VAL P$; because STR$ on a ZX81 never produces a trailing .0 for integers, this correctly detects integer values.
Keypress Pause
Line 2302 uses IF INKEY$<>"" THEN PAUSE 40000 — if any key is held during scrolling output, it triggers a long pause, giving the user time to read the screen. This is a common ZX81 technique since there is no built-in “press any key to continue” facility.
Anomalies and Notes – Program 1
- Line 2110 is
REM(empty remark) — it appears to be a vestigial page-break handler stub; the counterCis incremented at 2315 and checked at 2100, but the only action taken is resettingC=0with no actual page-break output. - The rounding bias of
+0.05(rather than the standard+0.5) at lines 2070 and 2140 introduces a systematic downward rounding bias for values with three or more decimal places, which may cause the running principalPto drift slightly over a long schedule. - Line 1110 truncates
Y$to its first character, ensuring only “Y” or “N” is compared later.
Program 2 – Prepayment Savings Calculator
Program Structure
- Lines 10–50: Optional instructions display, gated by
PAUSE 40000/INKEY$keypress. - Lines 60–100: Multi-screen instruction text about prepayment savings.
- Lines 190–299: Input — mortgage amount
P, yearsY, interest rateR, hard-copy flag viaINKEY$. - Lines 300–379: Column header output to screen or printer.
- Lines 380–640: Outer loop over
Q(years remaining, descending); inner loop at 520 simulates one full year. - Lines 650–730: Summary output, then
RUNto restart. - Lines 1000–1010: GOSUB captures original payment
OP. - Lines 2000–2020: GOSUB formats and LPRINTs one row.
- Lines 3000–3050: GOSUB prints header to printer.
Hard-Copy Input Technique
Lines 294–296 use a polling loop on INKEY$ rather than INPUT to capture the hard-copy flag. This avoids requiring the user to press ENTER after a single keypress, giving a more responsive feel.
Effective Interest Rate Calculation
Lines 582–585 compute a scaled “effective interest rate” IR for display. The interest component of the current payment minus the principal-only portion is computed, then normalised against its value at the original term (ZZ, saved at line 583), and scaled by the nominal rate R. This produces an approximate effective rate column rather than the nominal rate, though the methodology is heuristic rather than actuarially precise.
Extra Payment Column
EM at line 570 is INT((M - OP)*100 + 0.05)/100 — the difference between the current scenario’s payment and the original full-term payment, representing how much extra per month would be needed to pay off in Y years rather than YY years.
Dollars Saved Column
MX (line 510) holds the total cost of the mortgage at the original term. MY = Y*M*12 is the total cost at the current (shorter) term. The column INT(MX-MY) is the gross saving, truncated to whole dollars.
Anomalies and Notes – Program 2
| Line | Issue |
|---|---|
| 530 | A = INT(P*I*100*100+0.5)/100 — multiplies by 10000 then divides by 100, yielding a value 100× too large for the interest component. This appears to be a bug: the division should be by 10000, or the multiply should be by 100. The result is that A (interest portion) and B (principal portion) in this program are scaled incorrectly, though since only the payment total M is displayed rather than the split, the visible output is unaffected. |
| 591 | IF YY-Q>14 THEN PAUSE 10000 — after 14 rows have scrolled, a pause is inserted to prevent the display from scrolling past readable range. This is a pragmatic screen-paging substitute. |
| 570 | Uses rounding bias +0.05 instead of +0.5 for two decimal places — same systematic issue as Program 1. |
| 80–90 | Long string literals exploit the ZX81’s ability to wrap display across multiple screen lines within a single PRINT statement, producing formatted multi-paragraph text from two lines of BASIC. |
Shared Idioms Across Both Programs
- DIM spacer string: Both programs DIM a 32-character string (
C$/Z$) and slice it to generate right-aligned padding for LPRINT columns. - FAST/SLOW switching: Both switch to FAST mode for computation and SLOW for display, maximising calculation speed while keeping output readable.
- Iterative power: Both compute
(1+I)^Nvia a FOR loop, working around the absence of a general exponentiation function for this use case. - RUN at line 9999: Both end with
RUNto restart after completion, creating a continuous-loop kiosk-style operation.
Content
Source Code
10 LET C=0
20 DIM C$(32)
30 SLOW
100 PRINT AT 0,3;"% %M%O%R%T%G%A%G%E% %P%A%Y%M%E%N%T% %A%N%A%L%Y%S%I%S% "
1000 PRINT ,,"PRINCIPAL OR MORTGAGE AMOUNT LEFT TO BE PAID? ";
1010 INPUT P
1020 PRINT P
1030 PRINT ,,"TOTAL NUMBER OF MONTHS OR PERIODS LEFT? ";
1040 INPUT L
1050 PRINT L
1060 PRINT ,,"ANNUAL INTEREST RATE? ";
1070 INPUT R
1080 PRINT R
1090 PRINT ,,"DO YOU WANT HARD COPY?"
1100 INPUT Y$
1110 LET Y$=Y$(1)
1120 PRINT ,,"STARTING WITH WHAT PERIOD?"
1130 INPUT WP
1900 FAST
2000 LET I=R/1200
2010 LET T=1
2020 FOR N=1 TO L
2030 LET T=T*(1+I)
2040 NEXT N
2050 LET T=1-(1/T)
2060 LET M=P*I/T
2070 LET M=INT (M*100+.05)/100
2090 FOR N=1 TO L
2100 IF C<13 THEN GOTO 2140
2110 REM
2120 LET C=0
2140 LET A=(INT (P*I*100+.05))/100
2150 LET B=M-A
2160 LET P=P-B
2170 SCROLL
2185 IF WP>N THEN GOTO 2310
2186 IF Y$="Y" THEN GOTO 2310
2190 PRINT "PAYMT NUMBER",N
2200 SCROLL
2210 PRINT "PRINCIPAL LEFT",P
2220 SCROLL
2230 PRINT "PER. PAYMT.",M
2240 SCROLL
2250 PRINT "PRINCIPAL/PER.",B
2260 SCROLL
2270 PRINT "INTEREST/PER.",A
2280 FOR Z=1 TO 3
2290 SCROLL
2300 NEXT Z
2302 IF INKEY$<>"" THEN PAUSE 40000
2305 SLOW
2310 GOSUB 3000
2315 LET C=C+1
2320 NEXT N
2500 STOP
3000 IF WP>N OR Y$<>"Y" THEN RETURN
3010 LET B$="PAYMENT NUMBER"+C$( TO 18-LEN STR$ N)+STR$ N
3020 LPRINT B$
3030 LET P$=STR$ P
3040 GOSUB 3500
3050 LET B$="PRINCIPAL LEFT"+C$( TO 18-LEN P$)+P$
3070 LPRINT B$
3080 LET P$=STR$ M
3090 GOSUB 3500
3100 LET B$="PERIOD PAYMENT"+C$( TO 18-LEN P$)+P$
3110 LPRINT B$
3120 LET P$=STR$ B
3130 GOSUB 3500
3140 LET B$="PD. PRINC./PER."+C$( TO 17-LEN P$)+P$
3150 LPRINT B$
3160 LET P$=STR$ A
3170 GOSUB 3500
3180 LET B$="PD. INTEREST/PER."+C$( TO 15-LEN P$)+P$
3190 LPRINT B$
3200 LPRINT
3210 LPRINT
3220 RETURN
3500 LET PP=VAL P$
3510 LET PP=INT (100*PP+.05)/100
3520 LET P$=STR$ PP
3530 IF VAL P$=INT VAL P$ THEN LET P$=P$+".00"
3540 IF 10*VAL P$=INT (10*VAL P$) THEN LET P$=P$+"0"
3550 RETURN
9998 SAVE "MORTGAGE ANALYSI%S"
9999 RUN
10 LET YS=0
15 DIM Z$(32)
20 LET A$="..............................."
30 PRINT "%I%N%S%T%R%U%C%T%I%O%N%S%?"
40 PAUSE 40000
50 IF INKEY$<>"Y" THEN GOTO 190
60 CLS
70 PRINT "%H%O%W% %T%O% %S%A%V%E% %M%O%N%E%Y% %O%N% %A% %M%O%R%T%G%A%G%E"
80 PRINT ,," THIS PROGRAM IS DESIGNED TO SHOW YOU HOW BY PAYING A SMALL ADDIONAL AMOUNT TO A MONTHLY MORTGAGE PAYMENT CAN PRODUCE A DRASTIC CHANGE IN THE LIFE AND FINAL AMOUNT PAID INTO A MORT- GAGE."
90 PRINT " YOU MAY BE SUPRISED HOW A LITTLE MORE MONEY ADDED TO A MONTHLY PAYMENT CAN SUBTRACT YEARS AND THOUSANDS OF DOLLARS FROM THE ORIGINAL TOTALS, PAR- TICULARLY AT TODAY' S 29 AND 30 YEAR MATURITIES AND DOUBLE DIGITINTEREST RATES."
100 PRINT AT 21,0;"PRESS ENTER TO CONTINUE :::"
110 INPUT B$
190 CLS
200 PRINT "WHAT IS THE ORIGINAL OR REMAIN- ING AMOUNT OF THE MORTGAGE?"
205 SLOW
210 INPUT P
220 LET PP=P
230 PRINT ,,"HOW MANY YEARS ARE LEFT TO PAY?"
240 INPUT Y
260 LET L=12*Y
270 LET YY=Y
280 PRINT ,,"WHAT IS THE INTEREST RATE?"
290 INPUT R
292 PRINT ,,"DO YOU WANT HARD COPY?"
294 LET Y$=INKEY$
296 IF Y$="" THEN GOTO 294
300 CLS
310 FAST
315 IF Y$="Y" THEN GOTO 365
320 SCROLL
325 PRINT A$
326 SCROLL
330 PRINT "TTL MON EFF XTR $"
335 SCROLL
340 PRINT "YRS PYMT INT PER SAVED"
350 SCROLL
360 PRINT " RT. MON"
365 IF Y$="Y" THEN GOSUB 3000
366 IF Y$="Y" THEN GOTO 380
370 SCROLL
375 PRINT A$
376 SCROLL
380 FOR Q=Y TO 1 STEP -1
390 FAST
400 LET I=R/1200
410 LET T=1
420 FOR X=1 TO L
430 LET T=T*(1+I)
440 NEXT X
450 LET T=1/T
460 LET T=1-T
470 LET M=P*I/T
480 LET M=INT (M*100+.5)/100
490 IF YY<>Y THEN GOTO 520
500 LET MX=INT ((PP*I/T)*100+.5)/100
510 LET MX=MX*12*YY
520 FOR Z=1 TO L
530 LET A=(INT (P*I*100*100+.5))/100
540 LET B=M-A
550 LET P=P-B
560 IF YS=0 THEN GOSUB 1000
570 LET EM=INT ((M-OP)*100+.05)/100
580 LET MY=Y*M*12
582 LET IR=M-(PP/(Y*12))
583 IF Y=YY THEN LET ZZ=IR
584 LET IR=R*(IR/ZZ)
585 LET IR=INT ((IR)*100+.05)/100
586 IF Y$="Y" THEN GOTO 592
588 SCROLL
590 PRINT Y;TAB 3;M;TAB 11;IR;TAB 17;EM;TAB 25;INT (MX-MY)
591 IF YY-Q>14 THEN PAUSE 10000
592 IF Y$="Y" THEN GOSUB 2000
600 LET P=PP
610 LET YS=YS+1
620 LET L=L-12
630 LET Y=Y-1
640 NEXT Q
650 SCROLL
660 PRINT A$
665 SCROLL
670 PRINT "ORIGINAL MORTGAGE IF PAID IN"
680 SCROLL
690 PRINT YY;" YEARS WOULD COST $";MX
700 IF Y$="Y" THEN LPRINT "ORIGINAL MORTGAGE IF PAID IN"
710 IF Y$="Y" THEN LPRINT YY;" YEARS WOULD COST $";MX
720 PAUSE 1000
730 CLS
740 RUN
1000 LET OP=M
1010 RETURN
2000 LET B$=STR$ Y+Z$( TO 3-LEN STR$ Y)+STR$ M+Z$( TO 8-LEN STR$ M)+STR$ IR+Z$( TO 6-LEN STR$ IR)+STR$ EM+Z$( TO 8-LEN STR$ EM)+STR$ (MX-MY)
2010 LPRINT B$
2020 RETURN
3000 LPRINT A$
3010 LPRINT "TTL MON EFF XTR $"
3020 LPRINT "YRS PYMT INT PER SAVED"
3030 LPRINT " RT. MON"
3040 LPRINT A$
3050 RETURN
9998 SAVE "PREPAYMEN%T"
9999 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.


