Boost :: accumulators :: roll_mean returns an invalid average

Environment: VS 2013, Boost 1.58

I wrote something that is a friendlier interface for the Boost battery, which you can use to create a sum over the window, and calculate the actual moving average of the window. While clicking to switch to VS 2013 as the main compiler, one of the unit tests for this class started to fail. Exfoliating the layers, I 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 last pass of the cycle, I don't get the expected average value (1.5), but instead get a crazy high value (1431655766.333333).

This code runs correctly in VS 2008 with Boost 1.49 (with the initialization of the C ++ 11 vector, obviously), but with an error in VS 2012 and VS 2013 with Boost 1.58. I find it difficult to explain this error and, therefore, cannot fix it.

Other interesting points:

  • Manually checking the memory values ​​inside the battery shows that its ring buffer contains the correct data.
  • If the data stored in the drive is ordered in increasing order, the roll_mean value will be correct.
  • As soon as the window is filled, if any new element is less than the number that it knocks out of the window, the roll_mean value will be incorrect. If it is equal to or greater, the roll_mean value will be correct.

This seems to be a Boost bug, but I wanted to check that I wasn’t doing something stupid before reporting an error or trying to create Boost 1.59. Thanks in advance!

EDIT: Thanks for the answers as this seems like a Boost bug. The related Boost ticket is here. . This is an unsigned integer problem with batteries. In particular, if the value added to the drive after the window is full is strictly less than all the values ​​in the window, the roll_mean call will return an incorrect result.

There is a workaround that should not use unsigned integers with batteries. This solves my problem, so thanks for the help!

+5
source share
1 answer

Obviously, there is an error there, perhaps in the compiler, but most likely in the library, since I was 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"; } } 

Print

 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 is with the choice of unsigned sample type : changing it to a signature eliminates the symptom: Live On Coliru


In short : I would report this on the boost or Trac mailing list: https://svn.boost.org/trac/boost/

+8
source

Source: https://habr.com/ru/post/1233001/


All Articles