Last active
September 15, 2015 05:27
-
-
Save martinmoene/0205cd59c8e1dfbbe235 to your computer and use it in GitHub Desktop.
Simple running average (mean and median) of samples in C++.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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