Boost logo

Boost Users :

Subject: Re: [Boost-users] Accumulators: Using data vector from Interprocess
From: Eric Niebler (eric_at_[hidden])
Date: 2008-12-23 14:19:06


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 <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

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net