This program performs multiple linear regression using matrix operations implemented entirely in BASIC. It accepts user input for observations and independent variables, then computes regression coefficients by solving the normal equations via the formula (X’X)⁻¹X’Y, relying on subroutines at lines 7300 (matrix multiplication) and 7500 (matrix inversion). The matrix inversion routine at line 7500 uses Gauss-Jordan elimination with partial pivoting and detects singular matrices by setting an error string E$. A utility routine starting at line 9000 uses direct PEEK and POKE operations on the system’s program area—reading the D_FILE system variable at address 16396/16397 and walking the BASIC line-length bytes—to delete a range of program lines from memory, allowing optional removal of unused subroutines to free RAM.
Program Analysis
Program Structure
The program is divided into four logical blocks:
- Lines 1000–1900: Main routine — data entry, matrix setup, computation of regression coefficients, and display of results.
- Lines 7000–7665: Matrix operation subroutine library (scalar multiply, add/subtract, multiply, transpose, inversion).
- Lines 8000–8010: SAVE utility.
- Lines 9000–9210: Self-modifying line-deletion utility using PEEK/POKE on the BASIC program area.
Regression Algorithm
The program computes ordinary least-squares regression coefficients using the normal equation solution β = (X'X)⁻¹ X'Y. The implementation proceeds in steps:
- Build design matrix
X(NOB, NV+1)with the first column fixed to 1 (for the intercept). - Compute
X'Yby calling the matrix multiplication subroutine (line 7300) with the transpose of X and Y. The result is stored inT(NV+1, 1). - Compute
X'Xby multiplying transposed X by X, storing the result inA(NV+1, NV+1). - Invert
X'Xvia GOSUB 7500 (Gauss-Jordan elimination). - Multiply the inverse by
X'Y(GOSUB 7300) to obtain the coefficient vectorC.
Lines 1830–1860 print both actual and predicted values (rounded to two decimal places using INT(P*100+.5)/100), but no residuals, R², or other statistics are computed.
Matrix Subroutine Library (7000-block)
| Line | Operation | Inputs | Output |
|---|---|---|---|
| 7100 | Scalar multiplication | SCALAR, A, ROWA, COLA | C = SCALAR * A |
| 7200 | Matrix add/subtract | A, B, ROWA, COLA, SIGN | C = A ± B |
| 7300 | Matrix multiplication | A, B, ROWA, COLA, COLB | C = A * B |
| 7400 | Matrix transposition | A, ROWA, COLA | C = A' |
| 7500 | Matrix inversion | A, ROWA | C = A⁻¹ |
Note that subroutines 7100, 7200, and 7400 are defined and documented but never called by the main regression routine — they are included as a general-purpose library.
Matrix Inversion (Gauss-Jordan, line 7500)
The inversion routine implements Gauss-Jordan elimination with partial pivoting. It initializes C as the identity matrix (lines 7505–7520), then for each pivot column searches downward for a non-zero element. If none is found the matrix is singular and E$ is set to "SINGULAR MATRIX" before returning. Row swaps are applied simultaneously to both A and C (lines 7555–7590). Each pivot row is normalized by dividing by A(J,J), and all other rows are reduced. The variable E$ is initialized to an empty string at line 7502 but is never checked by the calling code — any singular-matrix condition would silently return an incorrect result.
Transposition Approach
Rather than calling the transposition subroutine at line 7400, the main code manually constructs the transpose of X into array A at lines 1220–1290. This avoids an extra array copy but means the transposition subroutine is unused by the main algorithm. Similarly, B is populated with a copy of Y at lines 1320–1350 and later with a copy of X at lines 1430–1480, reflecting how the subroutines communicate through global arrays.
Notable Techniques
- Global array passing convention: All subroutines communicate via globally named arrays
A,B,C, and dimension variablesROWA,COLA,COLB. Arrays must be re-dimensioned before each subroutine call. - Rounding display: Predicted values are rounded to two decimal places using the idiom
INT(P*100+.5)/100at line 1850. - Input validation: After each observation is entered, the user is asked “CORRECT?” and the observation is re-entered if the first character of the response is not “Y” (line 1180), using substring indexing
A$(1). - Matrix multiplication bug: The multiplication loop at lines 7320–7380 accumulates into
C(I,J)without initializing it to zero first. BecauseCis freshly DIMmed at line 7310, its elements are zero-initialized, so this works correctly on the first call. However, if the sameCarray were reused without re-dimensioning, results would be incorrect.
Line-Deletion Utility (9000-block)
Lines 9000–9210 implement a self-modifying routine that deletes a range of BASIC lines by directly manipulating the program’s byte representation in memory. It reads the D_FILE system variable from addresses 16396–16397 to find the end of the program, then walks the program line by line using the two-byte line-length field at offset 2–3 of each line header. Once the byte positions of the first and last lines to delete are found, it overwrites the length bytes of the first retained line to span over the deleted block, effectively compressing them out of the program. This is a sophisticated and risky technique, as any miscalculation could corrupt the program or system variables.
The intended purpose is to allow the user to delete unused subroutines (e.g., 7100, 7200, 7400) to reclaim RAM after loading the program on a memory-constrained system.
Content
Source Code
1000 CLS
1010 PRINT "NUMBER OF OBSERVATIONS=";
1020 INPUT NOB
1030 PRINT NOB
1040 PRINT "NO. INDEP. VARIABLES =";
1050 INPUT NV
1060 PRINT NV
1070 PRINT
1080 DIM X(NOB,NV+1)
1085 DIM Y(NOB,1)
1090 FOR I=1 TO NOB
1095 LET X(I,1)=1
1097 CLS
1100 PRINT ,,"OBSERVATION ",I,,,
1102 PRINT " DEP. VAR. = ",
1103 INPUT Y(I,1)
1104 PRINT Y(I,1)
1105 FOR J=2 TO NV+1
1110 PRINT " VAR ";J;" = ",
1120 INPUT X(I,J)
1130 PRINT X(I,J)
1140 NEXT J
1150 PRINT
1160 PRINT "CORRECT?"
1170 INPUT A$
1180 IF A$(1)<>"Y" THEN GOTO 1097
1190 NEXT I
1200 REM %T%R%A%N%S%O%S%E% %X
1220 LET ROWA=NV+1
1225 LET COLA=NOB
1230 DIM A(ROWA,COLA)
1240 FOR I=1 TO COLA
1250 FOR J=1 TO ROWA
1260 LET A(J,I)=X(I,J)
1280 NEXT J
1290 NEXT I
1300 LET ROWB=NOB
1310 LET COLB=1
1320 DIM B(ROWB,COLB)
1330 FOR I=1 TO ROWB
1340 LET B(I,1)=Y(I,1)
1350 NEXT I
1360 GOSUB 7300
1370 DIM T(NV+1,1)
1380 FOR I=1 TO NV+1
1390 LET T(I,1)=C(I,1)
1400 NEXT I
1410 LET ROWB=NOB
1420 LET COLB=NV+1
1430 DIM B(ROWB,COLB)
1440 FOR I=1 TO ROWB
1450 FOR J=1 TO COLB
1460 LET B(I,J)=X(I,J)
1470 NEXT J
1480 NEXT I
1490 GOSUB 7300
1500 DIM A(NV+1,NV+1)
1510 LET ROWA=NV+1
1520 LET COLA=NV+1
1530 FOR I=1 TO ROWA
1540 FOR J=1 TO COLA
1550 LET A(I,J)=C(I,J)
1560 NEXT J
1570 NEXT I
1580 LET ROWB=NV+1
1590 LET COLB=1
1600 DIM B(ROWB,COLB)
1610 FOR I=1 TO ROWB
1630 LET B(I,1)=T(I,1)
1640 NEXT I
1650 GOSUB 7500
1660 FOR I=1 TO ROWA
1670 FOR J=1 TO COLA
1680 LET A(I,J)=C(I,J)
1690 NEXT J
1700 NEXT I
1710 GOSUB 7300
1800 FOR I=1 TO NV+1
1810 PRINT I,C(I,1)
1820 NEXT I
1830 FOR I=1 TO NOB
1832 LET P=0
1835 FOR J=1 TO NV+1
1840 LET P=P+C(J,1)*X(I,J)
1845 NEXT J
1850 PRINT Y(I,1),INT (P*100+.5)/100
1860 NEXT I
1900 STOP
7000 REM %T%H%E% %S%U%B%R%O%U%T%I%N%E%S% %I%N% %T%H%E% %7%0%0%0% %B%L%O%C%K% %O%F% %T%H%I%S% %P%R%O%G%R%A%M% %A%R%E% %T%H%E% %M%A%T%R%I%X% %O%P%E%R%A%T%I%O%N%S%.% %7%1%0%0% %=% %S%C%A%L%A%R% %M%U%L%T%I%P%L%I%C%A%T%I%O%N%,% %7%2%0%0% %=% %M%A%T%R%I%X% %A%D%D%I%T%I%O%N% %A%N%D% %S%U%B%T%R%A%C%T%I%O%N%,% %7%3%0%0% %=% %M%A%T%R%I%X% %M%U%L%T%I%P%L%I%C%A%T%I%O%N%,% %7%4%0%0% %=% %M%A%T%R%I%X% %T%R%A%N%S%P%O%S%I%T%I%O%N%,% %7%5%0%0% %=% %M%A%T%R%I%X% %I%N%V%E%R%S%I%O%N%.
7100 REM %S%C%A%L%A%R% %M%U%L%T%I%P%L%I%C%A%T%I%O%N%:%I%N%P%U%T%S%:% %S%C%A%L%A%R%,% %A% %(%M%A%T%R%I%X%)%,% %R%O%W%A%,% %C%O%L%A%.% %O%U%T%P%U%T%:% %C% %(%M%A%T%R%I%X%)% %W%H%E%R%E% %C%=%S%C%A%L%A%R%*%A
7110 DIM C(ROWA,COLA)
7120 FOR I=1 TO ROWA
7130 FOR J=1 TO COLA
7140 LET C(I,J)=SCALAR*A(I,J)
7150 NEXT J
7160 NEXT I
7170 RETURN
7200 REM %M%A%T%R%I%X% %A%D%D%I%T%I%O%N% %A%N%D% %S%U%B%T%R%A%C%T%I%O%N%.% %I%N%P%U%T%S%:% %A% %(%M%A%T%R%I%X%)%,% %B% %(%M%A%T%R%I%X%)%,% %R%O%W%A%,% %C%O%L%A%,% %S%I%G%N% %(%+%1% %F%O%R% %A%D%D%,% %-%1% %F%O%R% %S%U%B%T%.%)%.% %O%U%T%P%U%T%S%:% %C% %(%M%A%T%R%I%X%)% %W%H%E%R%E% %C%=%A%+% %O%R% %-%B%.
7210 DIM C(ROWA,COLA)
7220 FOR I=1 TO ROWA
7230 FOR J=1 TO COLA
7240 LET C(I,J)=A(I,J)+SIGN*B(I,J)
7250 NEXT J
7260 NEXT I
7270 RETURN
7300 REM %M%A%T%R%I%X% %M%U%L%T%I%P%L%I%C%A%T%I%O%N%.% %I%N%P%U%T%S% %A% %(%M%A%T%R%I%X%)%,% %B% %(%M%A%T%R%I%X%)%,% %R%O%W%A%,% %C%O%L%A%,% %C%O%L%B%.% %O%U%T%P%U%T%S%:% %C% %(%M%A%T%R%I%X%)% %W%H%E%R%E% %C%=%A%*%B%.
7310 DIM C(ROWA,COLB)
7320 FOR I=1 TO ROWA
7330 FOR J=1 TO COLB
7340 FOR K=1 TO COLA
7350 LET C(I,J)=C(I,J)+A(I,K)*B(K,J)
7360 NEXT K
7370 NEXT J
7380 NEXT I
7390 RETURN
7400 REM %M%A%T%R%I%X% %T%R%A%N%S%P%O%S%I%T%I%O%N%.% %I%N%P%U%T%S%:% %A% %(%M%A%T%R%I%X%)%,% %R%O%W%A%,% %C%O%L%A%.% %O%U%T%P%U%T%S%:% %C% %(%M%A%T%R%I%X%)% %W%H%E%R%E% %C%=%A%"%.
7410 DIM C(ROWA,COLA)
7420 FOR I=1 TO ROWA
7430 FOR J=1 TO COLA
7440 LET C(I,J)=A(J,I)
7450 NEXT J
7460 NEXT I
7470 RETURN
7500 REM %M%A%T%R%I%X% %I%N%V%E%R%S%I%O%N%.% %I%N%P%U%T%S%:% %A% %(%M%A%T%R%I%X%)%,% %R%O%W%A%.% %O%U%T%P%U%T%S%:% %C% %(%M%A%T%R%I%X%)% %W%H%E%R%E% %C%=%A%*%*%-%1%.
7502 LET E$=""
7505 DIM C(ROWA,ROWA)
7510 FOR J=1 TO ROWA
7515 LET C(J,J)=1
7520 NEXT J
7525 FOR J=1 TO ROWA
7530 FOR I=J TO ROWA
7535 IF A(I,J)<>0 THEN GOTO 7555
7540 NEXT I
7545 LET E$="SINGULAR MATRIX"
7550 RETURN
7555 FOR K=1 TO ROWA
7560 LET TEMP=A(J,K)
7565 LET A(J,K)=A(I,K)
7570 LET A(I,K)=TEMP
7575 LET TEMP=C(J,K)
7580 LET C(J,K)=C(I,K)
7585 LET C(I,K)=TEMP
7590 NEXT K
7595 LET TEMP=1/A(J,J)
7600 FOR K=1 TO ROWA
7605 LET A(J,K)=TEMP*A(J,K)
7610 LET C(J,K)=TEMP*C(J,K)
7615 NEXT K
7620 FOR L=1 TO ROWA
7625 IF L=J THEN GOTO 7655
7630 LET TEMP=-A(L,J)
7635 FOR K=1 TO ROWA
7640 LET A(L,K)=A(L,K)+TEMP*A(J,K)
7645 LET C(L,K)=C(L,K)+TEMP*C(J,K)
7650 NEXT K
7655 NEXT L
7660 NEXT J
7665 RETURN
8000 SAVE "REGRESSIO%N"
8010 STOP
9000 REM %D%E%L%E%T%E%S% %L%I%N%E%S% %O%F% %P%R%O%G
9005 CLS
9007 PRINT "FIRST LINE TO BE DELETED=";
9010 INPUT FIRSTLINE
9012 PRINT FIRSTLINE
9015 PRINT "LAST LINE TO BE DELETED=";
9020 INPUT LASTLINE
9022 PRINT LASTLINE
9030 PRINT
9032 PRINT "CORRECT?"
9034 INPUT Z$
9036 IF Z$(1)<>"Y" THEN GOTO 9000
9040 LET PROGBYTE=16509
9045 LET DFILE=PEEK 16396+256*PEEK 16397
9050 IF (256*PEEK PROGBYTE+PEEK (PROGBYTE+1))=FIRSTLINE THEN GOTO 9080
9060 LET PROGBYTE=PROGBYTE+4+PEEK (PROGBYTE+2)+256*PEEK (PROGBYTE+3)
9065 IF PROGBYTE>=DFILE THEN GOTO 9200
9070 GOTO 9050
9080 LET FIRSTLINE=PROGBYTE
9090 IF (256*PEEK PROGBYTE+PEEK (PROGBYTE+1))>LASTLINE THEN GOTO 9120
9100 LET PROGBYTE=PROGBYTE+4+PEEK (PROGBYTE+2)+256*PEEK (PROGBYTE+3)
9105 IF PROGBYTE>=DFILE THEN GOTO 9115
9110 GOTO 9090
9115 LET PROGBYTE=DFILE
9120 LET LASTLINE=PROGBYTE
9130 POKE (FIRSTLINE+2),(LASTLINE-FIRSTLINE-4)-256*INT ((LASTLINE-FIRSTLINE-4)/256)
9140 POKE (FIRSTLINE+3),INT ((LASTLINE-FIRSTLINE-4)/256)
9150 STOP
9200 PRINT "ERROR: FIRST LINE ";FIRSTLINE;" NOT FOUND."
9210 STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

