Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added moving_average windowing stats

  • Loading branch information...
commit c1425d4c1df38ebbd946a4a406b150bd2405028e 1 parent 4d3ad08
@saleyn authored
Showing with 98 additions and 8 deletions.
  1. +74 −8 include/utxx/running_stat.hpp
  2. +24 −0 test/test_running_stat.cpp
View
82 include/utxx/running_stat.hpp
@@ -63,20 +63,21 @@ template <typename CntType = size_t>
class basic_running_sum {
protected:
CntType m_count;
- double m_sum, m_min, m_max;
+ double m_last, m_sum, m_min, m_max;
public:
basic_running_sum() {
clear();
}
basic_running_sum(const basic_running_sum& rhs)
- : m_count(rhs.m_count), m_sum(rhs.m_sum)
- , m_min(rhs.m_min), m_max(rhs.m_max)
+ : m_count(rhs.m_count)
+ , m_last(rhs.m_last), m_sum(rhs.m_sum)
+ , m_min(rhs.m_min), m_max(rhs.m_max)
{}
/// Reset the internal state.
void clear() {
- m_count = 0; m_sum = 0.0; m_sum = 0.0;
+ m_count = 0; m_last = 0.0; m_sum = 0.0;
m_min = std::numeric_limits<double>::max();
m_max = std::numeric_limits<double>::min();
}
@@ -84,6 +85,7 @@ class basic_running_sum {
/// Add a sample measurement.
inline void add(double x) {
++m_count;
+ m_last = x;
m_sum += x;
if (x > m_max) m_max = x;
if (x < m_min) m_min = x;
@@ -104,16 +106,18 @@ class basic_running_sum {
}
/// Number of samples since last invocation of clear().
- CntType count() const { return m_count; }
- double sum() const { return m_sum; }
- double mean() const { return m_count > 0 ? m_sum / m_count : 0.0; }
+ CntType count() const { return m_count; }
+ bool empty() const { return !m_count; }
+
+ double last() const { return m_last; }
+ double sum() const { return m_sum; }
+ double mean() const { return m_count ? m_sum / m_count : 0.0; }
double min() const { return m_min == std::numeric_limits<double>::max()
? 0.0 : m_min; }
double max() const { return m_max == std::numeric_limits<double>::min()
? 0.0 : m_max; }
};
-
template <typename CntType = size_t>
class basic_running_variance : public basic_running_sum<CntType> {
typedef basic_running_sum<CntType> base;
@@ -152,6 +156,68 @@ class basic_running_variance : public basic_running_sum<CntType> {
double deviation() const { return sqrt(variance()); }
};
+template <typename T, int N = 0>
+struct basic_moving_average
+{
+ explicit basic_moving_average(size_t a_capacity = 0)
+ : MASK(N ? N-1 : a_capacity-1)
+ , m_data(m_samples)
+ {
+ #if __cplusplus >= 201103L
+ static_assert(!N || (N & (N-1)) == 0, "N must be 0 or power of 2");
+ #else
+ assert(!N || (N & (N-1)) == 0);
+ #endif
+ assert((N && !a_capacity) || (!N && a_capacity));
+ assert(!a_capacity || (a_capacity & (a_capacity-1)) == 0);
+ if (a_capacity)
+ m_data = new T[a_capacity];
+
+ clear();
+ }
+
+ ~basic_moving_average() {
+ if (m_data != m_samples)
+ delete [] m_data;
+ }
+
+ void add(T sample) {
+ if (m_full) {
+ T& oldest = m_data[m_size];
+ m_sum += sample - oldest;
+ oldest = sample;
+ } else {
+ m_data[m_size] = sample;
+ m_sum += sample;
+ }
+
+ if (!m_full && m_size == MASK)
+ m_full = true;
+
+ m_size = (m_size+1) & MASK;
+ }
+
+ void clear() {
+ memset(m_data, 0, capacity()*sizeof(T));
+ m_full = false;
+ m_sum = 0.0;
+ m_size = 0;
+ }
+
+ bool empty() const { return !m_full && !m_size; }
+ size_t capacity() const { return MASK+1; }
+ size_t samples() const { return m_full ? capacity() : m_size; }
+ double mean() const { return m_sum / ((m_full || !m_size) ? capacity() : m_size); }
+
+private:
+ const size_t MASK;
+ bool m_full;
+ size_t m_size;
+ double m_sum;
+ T* m_data;
+ T m_samples[N];
+};
+
/**
* Calculate a running weighted average of values on a given
* windowing interval using exponential decay.
View
24 test/test_running_stat.cpp
@@ -96,6 +96,30 @@ BOOST_AUTO_TEST_CASE( test_running_stat )
BOOST_REQUIRE_EQUAL(0.0, rs.deviation());
}
+BOOST_AUTO_TEST_CASE( test_running_stats_moving_average )
+{
+ basic_moving_average<int, 4> ma;
+
+ BOOST_REQUIRE_EQUAL(4u, ma.capacity());
+
+ ma.add(2); BOOST_REQUIRE_EQUAL(2.0, ma.mean());
+ ma.add(4); BOOST_REQUIRE_EQUAL(3.0, ma.mean());
+ ma.add(6); BOOST_REQUIRE_EQUAL(4.0, ma.mean());
+ ma.add(8); BOOST_REQUIRE_EQUAL(5.0, ma.mean());
+
+ BOOST_REQUIRE_EQUAL(4u, ma.samples());
+
+ ma.add(10); BOOST_REQUIRE_EQUAL(7.0, ma.mean());
+ ma.add(8); BOOST_REQUIRE_EQUAL(8.0, ma.mean());
+
+ BOOST_REQUIRE_EQUAL(4u, ma.samples());
+
+ ma.clear();
+
+ BOOST_REQUIRE_EQUAL(0u, ma.samples());
+ BOOST_REQUIRE_EQUAL(0.0, ma.mean());
+}
+
enum test_rs {
ONE
, TWO
Please sign in to comment.
Something went wrong with that request. Please try again.