--- title: "Moving Averages" id: 56306 type: "computer_media" slug: "movingaverages" url: "http://localhost/computer_media/movingaverages/" markdown_url: "http://localhost/computer_media/movingaverages.md" published_at: "2024-08-04T10:49:54+00:00" modified_at: "2026-03-30T21:44:10+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-jqhe.png" excerpt: "A time-series moving-averages program that handles even and odd periods, computes centred averages, and lets you chain multiple smoothing passes interactively." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Mathematics" slug: "mathematics" taxonomy: "genre" url: "http://localhost/type/mathematics/" media_contents: - id: 56277 title: "Timex Sinclair Public Domain Library Tape 2001" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2001/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/MovingAverages%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-jqhe.png" media_type_tags: "Mathematics" --- 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: 1. **Documentation display** (lines 2–9): Prints a variable glossary, pauses, then clears. 2. **Title display** (lines 20–50): Clears the screen and prints a title banner. 3. **Data input** (lines 70–130): READs `N` (number of periods) and `P` (window size) from DATA, then READs all observations into array `V()`. 4. **Moving average calculation** (lines 190–260): An outer loop over start positions and an inner summation loop compute raw moving averages into `U()`. 5. **Even-period centring** (lines 330–370): If `P` is even, a second pass averages adjacent `U()` values to produce a properly centred result. 6. **Results display** (lines 380–430): Prints each period index, observation, smoothed value, and ratio in a fixed-column tabular layout. 7. **User menu** (lines 450–540): Allows changing the base period, chaining a second moving average, or quitting. 8. **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)/100` is 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 to `P MOD 2 <> 0`. - **TAB-based column alignment**: Lines 400–410 use `TAB(2)`, `TAB(5)`, `TAB(16)`, and `TAB(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), `N` is reduced to `M1` but the arrays `V()` and `U()` retain their original size `N`. 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 large `P`, as `M` could become zero or negative. - **Truncation vs. rounding**: The use of `INT` truncates 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 `P` and the same data. The REM at line 60 (“DATA INPUT”) is bypassed, so the only way to change `P` is to edit line 610 directly. ## 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 ```