This program audits utility bills — electric, gas, water, and telephone — by accepting meter readings and billing period lengths, then calculating charges using up to three consumption tiers plus tax and manual adjustments. Each utility’s rate structure (monthly minimum, tier thresholds, and per-unit rates) is loaded from DATA statements at startup into parallel arrays. The phone bill module handles multiple residents sharing a line, collecting individual long-distance call charges one at a time into the w() array and splitting the base service charge proportionally. Results can be split among a configurable number of occupants, with the split count also stored in a DATA-driven array n().
Program Structure
The program is organised as a menu dispatcher with a shared calculation subroutine. Execution begins at line 340, which loads all rate data from DATA statements into arrays before falling through to the menu at line 410. The main menu (lines 410–555) routes to one of four utility handlers or an “all utilities” batch mode.
- Lines 340–400: Data initialisation — reads occupant counts
n(), then per-utility parameters into parallel arrays. - Lines 410–555: Menu display and dispatch.
- Lines 560–1010: Shared metered-utility subroutine (electric, gas, water) — prompts for readings, computes tiered charge, prints summary, offers split.
- Lines 1110–1580: Phone bill handler — loops over
n(4)persons, collects individual LD call amounts, verifies each entry, totals and taxes. - Lines 1590–1630: Batch mode — iterates utilities 1–3 via the shared subroutine, then falls through to the phone handler.
- Lines 1640–1690:
DATAblock andSTOP.
Data Layout
All rate parameters are held in parallel arrays indexed by utility number x (1=Electric, 2=Gas, 3=Water, 4=Phone).
| Array | Meaning |
|---|---|
n(x) | Number of occupants sharing the bill |
a$(x) | Utility name (e.g. “Electric”) |
b$(x) | Unit name (e.g. “KWH”, “CCF”) |
m(x) | Monthly minimum / base service charge |
z(x) | Tax rate (fractional) |
a(x) | Tier 1 upper threshold (units) |
b(x) | Tier 2 upper threshold (units) |
c(x) | Tier 1 rate (per unit) |
d(x) | Tier 2 rate (per unit) |
e(x) | Tier 3 rate (per unit) |
Gas and water are effectively single-tier utilities: gas uses an astronomically high tier threshold (99999) so only tier 1 ever applies, while water has a tier 2 threshold of 99999 to suppress the third tier.
Tiered Rate Calculation
The metered-utility subroutine implements a standard block-rate tariff at lines 740–800:
- Tier 1 (
u ≤ a(x)):t = m(x) + c(x)*u - Tier 2 (
a(x) < u ≤ b(x)):t = m(x) + c(x)*a(x) + d(x)*(u-a(x)) - Tier 3 (
u > b(x)): full staircase includinge(x)*(u-b(x))
Tax is computed as t1 = t * z(x) and the adjustment total a1 (from subroutine at line 110) is added last to give the final bill t3.
Key BASIC Idioms
- Sliced string printing:
a$(x, TO 8)andb$(x, TO 8)trim the fixed-length DIM strings to their content without trailing spaces causing layout problems. - Integer rounding:
INT (value * 100) / 100is used throughout to display monetary amounts to two decimal places, since there is no built-in formatting function. - Compound condition guard: Line
540usesIF (p<1)+(p>6) THEN— boolean addition as an OR, a classic Sinclair BASIC idiom. - Global variable reuse: The adjustment accumulator
a1, control variablex, and loop indexiare all unscoped globals shared across subroutine calls. - Input prompt confirmation: Line
605/635/665usePRINT ,valueafterINPUTto echo the entered value with a tab, providing visible confirmation.
Phone Bill Handler
The phone module (lines 1110–1580) is structurally distinct. It loops over n(4) persons, collecting LD call amounts one at a time into the w() array (dimensioned to 50 entries). After collection, a verification loop iterates over each call (FOR j=1 TO i-1) and offers a correction prompt before computing the per-person total.
Content
Source Code
10 REM A program for utility bills
90 DIM a$(4,8): DIM b$(4,8): DIM a(3): DIM b(3): DIM m(4): DIM c(3): DIM d(3): DIM e(3): DIM w(50): DIM z(4): DIM n(4)
100 GO TO 340
110 LET a1=0
120 PRINT " Input adjustments to bill (+ or - , ""0"" when done)"
130 INPUT f
140 LET a1=a1+f
150 IF f=0 THEN GO TO 170
160 GO TO 130
170 GO SUB 250
180 GO SUB 290
190 RETURN
200 CLS
210 RETURN
220 PRINT " ";a$(x, TO 8);" Bill (cont')"
230 PRINT
240 RETURN
250 FOR i=1 TO 3
260 PRINT
270 NEXT i
280 RETURN
290 PRINT "INPUT ""C"" to continue";
300 INPUT c$
310 GO SUB 200
320 RETURN
340 FOR i=1 TO 4
350 READ n(i)
360 NEXT i
370 FOR i=1 TO 3
380 READ a$(i),b$(i),m(i),z(i),a(i),b(i),c(i),d(i),e(i)
390 NEXT i
400 READ a$(4),m(4),z(4)
410 GO SUB 200
420 PRINT " UTILITY BILL AUDIT"
430 GO SUB 250
440 PRINT " 1. Electric Bill"
450 PRINT " 2. Gas Bill"
460 PRINT " 3. Water Bill"
470 PRINT " 4. Phone Bill"
480 PRINT " 5. All of the above"
490 PRINT " 6. Exit"
500 PRINT : PRINT
520 PRINT " CHOOSE an option ";
530 INPUT p
540 IF (p<1)+(p>6) THEN GO TO 530
550 IF p=1 THEN GO TO 1020
551 IF p=2 THEN GO TO 1050
552 IF p=3 THEN GO TO 1080
553 IF p=4 THEN GO TO 1110
554 IF p=5 THEN GO TO 1590
555 IF p=6 THEN GO TO 1690
560 GO SUB 200
570 PRINT " ";a$(x, TO 8);" Bill"
580 PRINT
590 PRINT "Previous meter reading:"
600 INPUT e1
605 PRINT ,e1
610 PRINT
620 PRINT "Present meter reading:"
630 INPUT e2
635 PRINT ,e2
640 PRINT
650 PRINT "Input days in the billing period:"
660 INPUT g
665 PRINT ,g
670 GO SUB 250
680 GO SUB 290
690 GO SUB 200
700 GO SUB 220
710 GO SUB 110
720 LET u=e2-e1
730 LET y=u/g
740 IF u>b(x) THEN GO TO 800
750 IF u>a(x) THEN GO TO 780
760 LET t=m(x)+c(x)*u
770 GO TO 810
780 LET t=m(x)+c(x)*a(x)+d(x)*(u-a(x))
790 GO TO 810
800 LET t=m(x)+c(x)*a(x)+d(x)*(b(x)-a(x))+e(x)*(u-b(x))
810 LET t1=t*z(x)
820 LET t2=t+t1
830 LET t3=t2+a1
840 GO SUB 200
850 GO SUB 220
860 PRINT "Use for the period is ";INT (u*100)/100;" ";b$(x, TO 8)
870 PRINT
880 PRINT "Use/Day is ";INT (y*100)/100;" ";b$(x, TO 8);" or $";
890 PRINT INT (t2/g*100)/100;"/Day including tax"
900 PRINT
910 PRINT a$(x, TO 8);" Bill:"
920 PRINT " W/out tax :$";INT (t*100)/100
930 PRINT " Tax is :$";INT (t1*100)/100
940 PRINT " ADJ'TS :$";a1
950 PRINT
960 PRINT " *TOTAL* :$";INT (t3*100)/100
970 IF n(x)=1 THEN GO TO 990
980 PRINT "SPLIT ";n(x);" ways:$";INT (t3/n(x)*100)/100
990 PRINT
1000 GO SUB 290
1010 RETURN
1020 LET x=1
1030 GO SUB 560
1040 GO TO 430
1050 LET x=2
1060 GO SUB 560
1070 GO TO 430
1080 LET x=3
1090 GO SUB 560
1100 GO TO 430
1110 GO SUB 200
1120 LET x=4
1130 PRINT " ";a$(x, TO 8);" Bill"
1140 PRINT
1150 GO SUB 110
1160 FOR k=1 TO n(x)
1170 LET i=1
1180 IF n(x)=1 THEN GO TO 1200
1190 PRINT "For person #";k;",";
1200 PRINT "INPUT charge for each long distance call (INPUT ""0"" when done)"
1210 INPUT w(i)
1220 IF w(i)=0 THEN GO TO 1250
1230 LET i=i+1
1240 GO TO 1210
1250 GO SUB 200
1260 PRINT " Person #";k;",";
1270 FOR j=1 TO -1
1280 PRINT "Call #";j;" :$";w(j)
1290 PRINT
1300 PRINT "Is the correct? (Y/N)"
1310 INPUT c$
1320 IF c$="Y" OR c$="y" THEN GO TO 1350
1330 PRINT "Type in correction"
1340 INPUT w(j)
1350 PRINT
1360 NEXT j
1370 GO SUB 200
1380 GO SUB 220
1390 LET t=0
1400 FOR j=1 TO i-1
1410 LET t=t+w(j)
1420 NEXT j
1430 PRINT "SERVICE: $";INT (m(x)/n(x)*100)/100
1440 PRINT
1450 PRINT "LD calls: $";t
1460 PRINT
1470 PRINT "ADJ'TS : $";INT (a1/n(x)*100)/100
1480 PRINT
1490 LET t1=t+INT (m(x)/n(x)*100)/100
1500 LET t2=INT (t1*z(x)*100)/100
1510 PRINT "TOTAL TAX: $";t2
1520 PRINT : PRINT
1540 PRINT " TOTAL BILL: $";t1+t2+INT (a1/n(x)*100)/100
1550 GO SUB 250
1560 GO SUB 290
1570 NEXT k
1580 GO TO 430
1590 FOR h=1 TO 3
1600 LET x=h
1610 GO SUB 560
1620 NEXT h
1630 GO TO 1110
1640 DATA 2,1,2,4
1650 DATA "Electric","KWH",5.40,0,350,1300,.0495,.0565,.0541
1660 DATA "Gas","CCF",4.04,0,99999,99999,.49541,0,0
1670 DATA "Water","CCF",3.26,0,500,99999,.144,.160,0
1680 DATA "Phone",13.50,.03
1690 STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
