Skip to content

Instantly share code, notes, and snippets.

@martinmoene
Last active September 15, 2015 05:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinmoene/0205cd59c8e1dfbbe235 to your computer and use it in GitHub Desktop.
Save martinmoene/0205cd59c8e1dfbbe235 to your computer and use it in GitHub Desktop.
Simple running average (mean and median) of samples in C++.
//
// simple running average (mean and median) of samples.
//
#include <algorithm>
#include <cassert>
#include <numeric>
#include <vector>
#ifndef RUNLENGTH
# define RUNLENGTH 5
#endif
// Prevent havoc when no data is present yet in buffer:
// 1. don't obtain mean or median before a sample has been added, or
// 2. return appropriate value from mean() and median() when buffer is empty, or
// 3. start with a non-empty buffer, or
// 4. start with a non-empty buffer and overwrite the element with the first inserted value.
//
// Here 1. is assumed.
template< typename T, typename S = double >
class running_average
{
public:
typedef T value_type;
typedef S sum_type;
typedef std::vector<T> buffer_type;
typedef typename buffer_type::size_type size_type;
running_average( size_type N )
: index( 0 ), capacity( N )
{
assert( N > 0 );
buffer.reserve( N );
}
void add( value_type const & v )
{
if ( buffer.size() < capacity )
{
buffer.push_back( v );
}
else
{
buffer[ index ] = v;
}
++index; index %= capacity;
}
sum_type mean() const
{
assert( buffer.size() > 0 );
return std::accumulate( begin(buffer), end(buffer), sum_type() )
/ static_cast<int>( buffer.size() );
}
value_type median() const
{
assert( buffer.size() > 0 );
const int n2 = buffer.size() / 2;
buffer_type tmp( begin(buffer), end(buffer) );
std::nth_element( begin(tmp), begin(tmp) + n2, end(tmp) );
return tmp[n2];
}
buffer_type const & getimpl() const
{
return buffer;
}
private:
size_type index;
size_type capacity;
buffer_type buffer;
};
// -----------------------------------------------------------------------
#include <iostream>
template< typename T, typename S >
std::ostream & operator<<( std::ostream & os, running_average<T,S> const & av )
{
os << "{ ";
for( const auto & x : av.getimpl() )
{
os << x << ", ";
}
return os << " }";
}
template< typename T, typename S >
void print( T const & x, running_average<T,S> const & av )
{
std::cout << "x:" << x << " mean:" << av.mean() << " median:" << av.median() << " history: " << av << "\n";
}
#define dim(a) ( sizeof(a) / sizeof(0[a]))
int main()
{
int a[] = { 9, 10, 11, 12, 13, 14, 15, 99, 17, 18, 19, 20, 19, 18, 17, 16, 15 };
running_average<int,long> av( RUNLENGTH );
// print( 0, av );
for ( auto x : a )
{
av.add( x );
print( x, av );
}
}
#if 0
cl -EHsc -DRUNLENGTH=3 main.cpp && main.exe
g++ -Wall -DRUNLENGTH=3 -std=c++11 -o main.exe main.cpp && main.exe
#endif // 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment