This program performs time-series analysis using the moving averages method, reading a dataset of 36 observations and a period length of 12 from DATA statements. It computes centred moving averages, automatically applying a second-pass averaging step when the period is even (to re-centre the result), then prints each period’s observation, smoothed value, and ratio in a tabular layout. The user can interactively change the base period, apply a second moving average to the already-smoothed series, or quit. Intermediate results are stored in arrays V() and U() of dimension N, with the smoothed series being fed back into V() for a second-pass calculation.
Program Analysis
Program Structure
The program is divided into clearly labelled sections indicated by REM statements and line-number ranges referenced in the opening documentation block (lines 2–9). Execution flows as follows:
- Documentation display (lines 2–9): Prints a variable glossary, pauses, then clears.
- Title display (lines 20–50): Clears the screen and prints a title banner.
- Data input (lines 70–130): READs
N(number of periods) andP(window size) from DATA, then READs all observations into arrayV(). - Moving average calculation (lines 190–260): An outer loop over start positions and an inner summation loop compute raw moving averages into
U(). - Even-period centring (lines 330–370): If
Pis even, a second pass averages adjacentU()values to produce a properly centred result. - Results display (lines 380–430): Prints each period index, observation, smoothed value, and ratio in a fixed-column tabular layout.
- User menu (lines 450–540): Allows changing the base period, chaining a second moving average, or quitting.
- DATA (lines 600–650): 36 observations (12 per year, suggesting monthly data over three years), with a period of 12.
Moving Average Algorithm
The core calculation (lines 190–260) computes a simple P-point moving average. For each starting index I from 1 to M = N − P + 1, it sums V(I) through V(I+P−1) and divides by P, storing the truncated (not rounded) two-decimal result in U(I) via INT(100*(T/P))/100.
When P is even (tested at line 330 using the standard P <> 2*INT(P/2) odd/even idiom), the result would be offset by half a period. Lines 350–370 correct this by averaging each pair of consecutive U(K) values, reducing the usable count by one (hence M1 = M − 1). The ratio R at line 390 expresses each original observation as a proportion of its centred moving average, useful for identifying seasonal factors.
Interactive Chaining of Smoothing Passes
Option 2 (line 481) allows the user to apply a second moving average to the already-smoothed series. Lines 500–530 reassign N = M1, copy U(I) back into V(I), and zero out U(), before branching back to line 150. The counter C1 is incremented (line 490) and displayed in the heading at line 280, letting the user track which pass they are viewing. This reuse of existing arrays avoids any need to DIMension new storage.
Notable BASIC Idioms and Techniques
- Truncation to two decimal places:
INT(100*x)/100is used throughout (lines 250, 360, 390) instead of rounding, which can introduce small systematic downward bias. - Odd/even test:
P <> 2*INT(P/2)at line 330 is the canonical BASIC modulo-2 check, equivalent toP MOD 2 <> 0. - TAB-based column alignment: Lines 400–410 use
TAB(2),TAB(5),TAB(16), andTAB(28)to align four columns without any string formatting routines. - DATA-driven input: All 36 observations and both parameters are supplied via DATA lines, making it straightforward to substitute a different dataset by editing only lines 600–650.
- PAUSE 340 at line 20: Provides approximately a 17-second display of the variable glossary before auto-clearing — a common documentation technique.
Data Set
| Line | Content |
|---|---|
600 | N = 36 (total observations) |
610 | P = 12 (period window — monthly seasonality) |
620–650 | 36 floating-point values across three years |
Bugs and Anomalies
- Array reuse without re-DIM: When chaining a second pass (option 2),
Nis reduced toM1but the arraysV()andU()retain their original sizeN. This is safe — the extra elements are simply ignored — but could produce confusing output if the user attempted a third or further pass with a largeP, asMcould become zero or negative. - Truncation vs. rounding: The use of
INTtruncates rather than rounds, so a value like 1.999 displays as 1.99 rather than 2.00. This is a minor accuracy concern for a statistical tool. - Option 1 (“change base period”) does not prompt for a new P: Branching to line 150 simply reruns the calculation with the same
Pand the same data. The REM at line 60 (“DATA INPUT”) is bypassed, so the only way to changePis to edit line 610 directly.
Content
Source Code
2 REM "MOV AVGS"
4 PRINT " VARIABLES:": PRINT : PRINT
5 PRINT "N NUMBER OF PERIODS OBSERVED -Line 600"
6 PRINT "P RANGE OF PERIODS FOR THE MOVING AVERAGES- Line 610"
7 PRINT "R RATIO OF AVERAGE TO ORIGINAL OBSERVATION"
8 PRINT "V(I) OBSERVATION FOR PERIOD I -Line 620 to end"
9 PRINT "U(I) MOVING AVERAGE FOR PERIOD I"
10 REM
20 PAUSE 340: CLS : PRINT : PRINT
30 PRINT "TIME-SERIES ANALYSIS"
40 PRINT "BY MOVING AVERAGES"
50 PRINT "-------------------------------"
60 REM DATA INPUT
70 READ N,P
80 DIM V(N): DIM U(N)
100 FOR I=1 TO N
120 READ V(I)
130 NEXT I
140 LET C1=1
150 PRINT
160 PRINT "MOVING AVERAGE CALCULATION"
180 REM CALCULATION OF AVERAGES
190 LET M=N-P+1
200 FOR I=1 TO M
210 LET T=0
220 FOR J=1 TO P
230 LET T=T+V(I+J-1)
240 NEXT J
250 LET U(I)=INT (100*(T/P))/100
260 NEXT I
270 PRINT : PRINT
280 PRINT "CALCULATION #";C1;" BASED ON ";P; " PERIODS"
290 PRINT "-------------------------------"
300 PRINT "PER OBSERM SMOOTHED VALUE RATIO"
310 PRINT "-------------------------------"
320 LET M1=M
330 IF P<>2*INT (P/2) THEN GO TO 380
340 LET M1=M-1
350 FOR K=1 TO M1
360 LET U(K)=INT (100*(U(K)+U(K+1))/2)/100
370 NEXT K
380 FOR K=1 TO M1
390 LET R=INT (100*(V(K+INT (P/2))/U(K)))/100
400 PRINT TAB ( 2);K+INT (P/2);TAB ( 5);V(K+INT (P/2));
410 PRINT TAB ( 16);U(K);TAB ( 28);R
420 NEXT K
430 PRINT "-------------------------------"
440 PRINT : PRINT : PRINT
450 PRINT "CHANGE THE BASE PERIOD===> TYPE <1>"
460 PRINT "CALCULATE A SECOND"
465 PRINT " MOVING AVERAGE ==> TYPE <2>"
467 PRINT
470 INPUT "QUIT ===> TYPE <3> ? ";C
480 IF C=1 THEN GO TO 150
481 IF C=2 THEN GO TO 490
482 IF C=3 THEN GO TO 550
490 LET C1=C1+1
500 LET N=M1
510 FOR I=1 TO N
520 LET V(I)=U(I): LET U(I)=0
530 NEXT I
540 GO TO 150
550 STOP
600 DATA 36
610 DATA 12
620 DATA 144.02,125.17,142.15,153.08,152.27,131.12,139.43,136.73,136.94,151.28
630 DATA 172.20,187.55,141.48,178.47,127.19,142.19,148.43,149.43,141.18,135.64
640 DATA 144.69,171.95,153.60,188.92,128.93,137.30,159.05,154.75,138.11,140.96
650 DATA 126.49,152.18,149.19,137.01,191.35,187.35
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
