
Eric Niebler wrote:
A moving average accumulator is an often requested feature. I knocked one together as a proof-of-concept during the accumulators review, but never polished it. You can find it in this message:
Whoops, that's a rolling average algorithm for the time series library. The implementation for the accumulators library is considerably simpler. I just knocked this together, but it seems to work. /////////////////////////////////////////////////////////////////////////////// // Copyright 2008 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include <boost/circular_buffer.hpp> #include <boost/accumulators/framework/extractor.hpp> #include <boost/accumulators/framework/depends_on.hpp> #include <boost/accumulators/framework/accumulator_base.hpp> #include <boost/accumulators/framework/parameters/sample.hpp> #include <boost/accumulators/numeric/functional.hpp> namespace boost { namespace accumulators { BOOST_PARAMETER_NESTED_KEYWORD(tag, rolling_average_window_size, window_size) namespace impl { template<typename Sample> struct rolling_average_impl : accumulator_base { // for boost::result_of typedef typename numeric::functional::average<Sample, std::size_t>::result_type result_type; template<typename Args> rolling_average_impl(Args const & args) : sum_(args[sample | Sample()]) , buffer_(args[rolling_average_window_size]) { } rolling_average_impl(rolling_average_impl const &that) : sum_(that.sum_) , buffer_(that.buffer_) { this->buffer_.set_capacity(that.buffer_.capacity()); } template<typename Args> void operator ()(Args const & args) { this->push_back_(args[sample]); } result_type result(dont_care) const { BOOST_ASSERT(this->buffer_.size() != 0); return numeric::average(this->sum_, this->buffer_.size()); } private: rolling_average_impl &operator=(rolling_average_impl const &); void push_back_(Sample const &value) { if(this->buffer_.full()) { this->sum_ -= this->buffer_[0]; } this->sum_ += value; this->buffer_.push_back(value); } Sample sum_; circular_buffer<Sample> buffer_; }; } namespace tag { struct rolling_average : depends_on< > , tag::rolling_average_window_size { typedef accumulators::impl::rolling_average_impl< mpl::_1 > impl; }; } namespace extract { extractor<tag::rolling_average> const rolling_average = {}; } using extract::rolling_average; }} #include <iostream> #include <boost/accumulators/accumulators.hpp> int main() { using namespace boost; using namespace accumulators; accumulator_set<double, features< tag::rolling_average > > acc(tag::rolling_average::window_size = 5); acc(1.); std::cout << rolling_average(acc) << std::endl; acc(2.); std::cout << rolling_average(acc) << std::endl; acc(3.); std::cout << rolling_average(acc) << std::endl; acc(4.); std::cout << rolling_average(acc) << std::endl; acc(5.); std::cout << rolling_average(acc) << std::endl; acc(6.); std::cout << rolling_average(acc) << std::endl; acc(7.); std::cout << rolling_average(acc) << std::endl; return 0; } -- Eric Niebler BoostPro Computing http://www.boostpro.com