user
Computing the simple moving average of a series of numbers.

Task

Create a stateful function/class/instance that takes a period and returns a routine that takes a number as argument and returns a simple moving average of its arguments so far.

Description

A simple moving average is a method for computing an average of a stream of numbers by only averaging the last   P   numbers from the stream,   where   P   is known as the period.

It can be implemented by calling an initialing routine with   P   as its argument,   I(P),   which should then return a routine that when called with individual, successive members of a stream of numbers, computes the mean of (up to), the last   P   of them, lets call this   SMA().

The word   *stateful*   in the task description refers to the need for   SMA()   to remember certain information between calls to it:

* The period,   P
* An ordered container of at least the last   P   numbers from each of its individual calls.

*Stateful*   also means that successive calls to   I(),   the initializer,   should return separate routines that do   *not*   share saved state so they could be used on two independent streams of data.

Pseudo-code for an implementation of   SMA   is:

```
function SMA(number: N):
    stateful integer: P
    stateful list:    stream
    number:           average

    stream.append_last(N)
    if stream.length() > P:
        # Only average the last P elements of the stream
        stream.delete_first()
    if stream.length() == 0:
        average = 0
    else:    
        average = sum( stream.values() ) / stream.length()
    return average

```

See also

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | Tasks for calculating statistical measures | | | --- | --- | |  | | |  |  |  |  |  | | --- | --- | --- | --- | --- | |  | | in one go | moving *(sliding window)* | moving *(cumulative)* | | Mean | Arithmetic | Statistics/Basic  Averages/Arithmetic mean  Averages/Pythagorean means | Averages/Simple moving average |  | | Geometric | Averages/Pythagorean means |  |  | | Harmonic | Averages/Pythagorean means |  |  | | Quadratic | Averages/Root mean square |  |  | | Circular | Averages/Mean angle  Averages/Mean time of day |  |  | | Median | | Averages/Median |  |  | | Mode | | Averages/Mode |  |  | | Standard deviation | | Statistics/Basic |  | Cumulative standard deviation | | | |

---
assistant
(formerly Perl 6)

**Works with**: Rakudo version 2016.08

```
sub sma-generator (Int $P where * > 0) {
    sub ($x) {
        state @a = 0 xx $P;
        @a.push($x).shift;
        @a.sum / $P;
    }
}

# Usage:
my &sma = sma-generator 3;

for 1, 2, 3, 2, 7 {
    printf "append $_ --> sma = %.2f  (with period 3)\n", sma $_;
}

```

Output:

```
append 1 --> sma = 0.33  (with period 3)
append 2 --> sma = 1.00  (with period 3)
append 3 --> sma = 2.00  (with period 3)
append 2 --> sma = 2.33  (with period 3)
append 7 --> sma = 4.00  (with period 3)

```