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:
http://lists.boost.org/Archives/boost/2007/07/124979.php
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
#include
#include
#include
#include
#include
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::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
{
extractortag::rolling_average const rolling_average = {};
}
using extract::rolling_average;
}}
#include <iostream>
#include
int main()
{
using namespace boost;
using namespace accumulators;
accumulator_set >
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