Computing the simple moving average of a series of numbers.

The task is to:

*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.

Pseudocode 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

#include <iostream> #include <stddef.h> #include <assert.h> using std::cout; using std::endl; class SMA { public: SMA(unsigned int period) : period(period), window(new double[period]), head(NULL), tail(NULL), total(0) { assert(period >= 1); } ~SMA() { delete[] window; } // Adds a value to the average, pushing one out if nescessary void add(double val) { // Special case: Initialization if (head == NULL) { head = window; *head = val; tail = head; inc(tail); total = val; return; } // Were we already full? if (head == tail) { // Fix total-cache total -= *head; // Make room inc(head); } // Write the value in the next spot. *tail = val; inc(tail); // Update our total-cache total += val; } // Returns the average of the last P elements added to this SMA. // If no elements have been added yet, returns 0.0 double avg() const { ptrdiff_t size = this->size(); if (size == 0) { return 0; // No entries => 0 average } return total / (double) size; // Cast to double for floating point arithmetic } private: unsigned int period; double * window; // Holds the values to calculate the average of. // Logically, head is before tail double * head; // Points at the oldest element we've stored. double * tail; // Points at the newest element we've stored. double total; // Cache the total so we don't sum everything each time. // Bumps the given pointer up by one. // Wraps to the start of the array if needed. void inc(double * & p) { if (++p >= window + period) { p = window; } } // Returns how many numbers we have stored. ptrdiff_t size() const { if (head == NULL) return 0; if (head == tail) return period; return (period + tail - head) % period; } }; int main(int argc, char * * argv) { SMA foo(3); SMA bar(5); int data[] = { 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 }; for (int * itr = data; itr < data + 10; itr++) { foo.add(*itr); cout << "Added " << *itr << " avg: " << foo.avg() << endl; } cout << endl; for (int * itr = data; itr < data + 10; itr++) { bar.add(*itr); cout << "Added " << *itr << " avg: " << bar.avg() << endl; } return 0; }

Content is available under GNU Free Documentation License 1.2.