Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::accumulators::rolling_mean returning incorrect mean value

Environment: VS 2013, Boost 1.58

I've written something that presents a more friendly interface to Boost's accumulator, which can be used to project a sum over a window, and calculate the actual rolling mean over the window. During a push to get to VS 2013 as our main compiler, one of the unit tests for this class started failing. Peeling off the layers, I've narrowed it down to this minimal example:

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>

namespace ba = boost::accumulators;
namespace bt = ba::tag;
typedef ba::accumulator_set < uint32_t, ba::stats <bt::rolling_mean > > MeanAccumulator;

int main() {

    MeanAccumulator acc(bt::rolling_window::window_size = 5u);

    for (uint32_t i : { 3, 2, 1, 0 }) {
        acc(i);
        std::cout << i << " actualMean: " << std::fixed << boost::accumulators::rolling_mean(acc) << "\n";
    }
}

On the final pass of the loop, I don't get the expected mean value (1.5), but instead get a crazy high value (1431655766.333333).

This code executes correctly in VS 2008 with Boost 1.49 (with C++11 vector initialization replaced, obviously), but fails in VS 2012 and VS 2013 with Boost 1.58. I'm at a loss to explain this failure and thus can't fix it.

Other interesting points:

  • Manually inspecting the memory values inside the accumulator reveals that the correct data IS contained in its circular buffer.
  • If the data put into the accumulator is ordered in increasing value, the rolling_mean will be correct.
  • Once the window is full, if any new element is smaller than the number it is knocking out of the window, the rolling_mean will be incorrect. If it is equal or greater, the rolling_mean will be correct.

It seems to be a Boost bug, but wanted to verify that I'm not doing something stupid before reporting the bug or attempting to build Boost 1.59. Thanks in advance!

EDIT: Thanks for the responses, as this does appear to be a Boost bug. The associated Boost ticket is here.. It's an issue related to unsigned integers with accumulators. Specifically, if a value added to the accumulator after the window is full is strictly less than all values in the window already, the rolling_mean call will return an invalid result.

There is a workaround, which is to not use unsigned integers with accumulators. This solves my problem, so thanks for the help!

like image 746
iamtheddrman Avatar asked Oct 05 '15 20:10

iamtheddrman


1 Answers

There's obviously a bug lurking there, possibly in the compiler, but more likely in the library, as I've been able to reproduce this on GCC:

Live On Coliru

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>

namespace ba = boost::accumulators;
namespace bt = ba::tag;
typedef ba::accumulator_set < uint32_t, ba::stats <bt::rolling_mean > > MeanAccumulator;

int main() {

    MeanAccumulator acc(bt::rolling_window::window_size = 5u);

    for (uint32_t i : { 252, 189, 248, 154, 620, 885, 939, 196 }) {
        acc(i);
        std::cout << i << " actualMean: " << std::fixed << boost::accumulators::rolling_mean(acc) << "\n";
    }
}

Prints

g++-5.2 -std=c++1y -O2 -Wall -pedantic main.cpp && ./a.out
252 actualMean: 252.000000
189 actualMean: 220.500000
248 actualMean: 229.666667
154 actualMean: 210.750000
620 actualMean: 292.600000
885 actualMean: 419.200000
939 actualMean: 569.200000
196 actualMean: 858994018.000000

Now the problem appears to be related to the choice of unsigned sample type`: changing it to signed removes the symptom: Live On Coliru


In short: I'd report this at the boost mailing list or Trac: https://svn.boost.org/trac/boost/

like image 190
sehe Avatar answered Nov 03 '22 06:11

sehe