Troubles using boost::circular_buffer

I declare I use it: #include <boost/circular_buffer.hpp> I make my function: double calculateStdDev(const boost::circular_buffer<double>& input, double& mean, double& variance, double& stddev) { if (input.empty()) return 0.0; boost::circular_buffer<double>::const_iterator it = input.begin(), end = input.end(); double M = *it; double Q = 0.0; unsigned int count = 1; ++it; while (it != end) { unsigned int k = count; ++count; double del = *it - M; unsigned int j = k + 1; Q += k * (del * del) / j; M += del / j; ++it; } variance = Q / (count - 1); stddev = std::sqrt(variance); mean = M; return stddev; } This function doesn't need to know are care about the number of items in the buffer. It just makes one pass through the data, from it = inut.begin() to input.end(). This particular algorithm, BTW, provides a solution that is MUCH faster and much more accurate in some cases, than the two pass algorithm, and is much more accurate than the other single pass algorithms you may see recommended. But that isn't the point. In the header that provides the prototypes for the functions in this particular CPP file, I have: double calculateStdDev(const boost::circular_buffer<double>& input, double& mean, double& variance, double& stddev); And gcc v 4.3.4 gives me the following error: ../../include/distribution.moments.hpp:9: error: wrong number of template arguments (1, should be 2) /usr/local/include/boost/circular_buffer/base.hpp:70: error: provided for 'template<class T, class Alloc> class boost::circular_buffer' I am not sure I understand why. Does this mean that I have to make calculateStdDev a template function? E.g.: template <typename T> double calculateStdDev(const boost::circular_buffer<double, T>& input, double& mean, double& variance, double& stddev) { // and put the entire implementation here in the header instead of in the cpp file with the overloads for other types such as std::vector) } But, if that is the case, why is it possible to instantiate such a buffer using the following (as in the example)? boost::circular_buffer<int> cb(3); I must have missed something, but I don't know what. Cheers Ted

From: r.ted.byers@gmail.com Date: Thu, 12 Apr 2012 23:54:41 -0400 In the header that provides the prototypes for the functions in this particular CPP file, I have: double calculateStdDev(const boost::circular_buffer<double>& input, double& mean, double& variance, double& stddev); And gcc v 4.3.4 gives me the following error: ../../include/distribution.moments.hpp:9: error: wrong number of template arguments (1, should be 2) /usr/local/include/boost/circular_buffer/base.hpp:70: error: provided for 'template<class T, class Alloc> class boost::circular_buffer' I am not sure I understand why. The circular_buffer class template does take two arguments, but the forwarding header supplies a default argument to the second one (std::allocator<T>). Somehow that forward declaration is being missed. Does this mean that I have to make calculateStdDev a template function? E.g.: template <typename T>double calculateStdDev(const boost::circular_buffer<double, T>& input, double& mean, double& variance, double& stddev) { // and put the entire implementation here in the header instead of in the cpp file with the overloads for other types such as std::vector)} No, your code computation code isn't the problem. But, if that is the case, why is it possible to instantiate such a buffer using the following (as in the example)? boost::circular_buffer<int> cb(3); I must have missed something, but I don't know what. Yeah, that part of your code is seeing the defaulted argument. I looked up standard-deviation in Wikipedia, and I think you should compute your data in a different way: // Not testedclass mean_and_stddev_computer{ double m_, q_; unsigned long c_; public: typedef double argument_type, result_type; mean_and_stddev_computer() : m_(), q_(), c_() {} void operator ()( double sample ) { double const delta = sample - m_; m_ += delta / ++c_; q_ += delta * ( sample - m_ ); } double sample_variance() const { return (c_ > 1u) ? (q_ / (c_ - 1)) : 0; } double standard_variance() const { return c ? (q_ / c_) : 0; } double sample_stddev() const { return std::sqrt(sample_variance()); } double standard_stddev() const { return std::sqrt(standard_variance()); } double mean() const { return m_; } unsigned long count() const { return c_; } double variance() const {return sample_variance(); } double stddev() const { return sample_stddev(); } double operator ()() const { return stddev(); }}; Then your code would use this function object with std::for_each. It should work with anything that makes iterators, not just circular_buffer. If you're going to take the average from several buffers, make sure to get your function object to assigned the value of the return value of for_each, so the averaging data is carried over. Daryle W.

Thanks Daryle, I'll look into that.. Cheers Ted From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Daryle Walker Sent: April-17-12 5:10 AM To: Boost Users Subject: Re: [Boost-users] Troubles using boost::circular_buffer From: r.ted.byers@gmail.com Date: Thu, 12 Apr 2012 23:54:41 -0400 In the header that provides the prototypes for the functions in this particular CPP file, I have: double calculateStdDev(const boost::circular_buffer<double>& input, double& mean, double& variance, double& stddev); And gcc v 4.3.4 gives me the following error: ../../include/distribution.moments.hpp:9: error: wrong number of template arguments (1, should be 2) /usr/local/include/boost/circular_buffer/base.hpp:70: error: provided for 'template<class T, class Alloc> class boost::circular_buffer' I am not sure I understand why. The circular_buffer class template does take two arguments, but the forwarding header supplies a default argument to the second one (std::allocator<T>). Somehow that forward declaration is being missed. Does this mean that I have to make calculateStdDev a template function? E.g.: template <typename T> double calculateStdDev(const boost::circular_buffer<double, T>& input, double& mean, double& variance, double& stddev) { // and put the entire implementation here in the header instead of in the cpp file with the overloads for other types such as std::vector) } No, your code computation code isn't the problem. But, if that is the case, why is it possible to instantiate such a buffer using the following (as in the example)? boost::circular_buffer<int> cb(3); I must have missed something, but I don't know what. Yeah, that part of your code is seeing the defaulted argument. I looked up standard-deviation in Wikipedia, and I think you should compute your data in a different way: // Not tested class mean_and_stddev_computer { double m_, q_; unsigned long c_; public: typedef double argument_type, result_type; mean_and_stddev_computer() : m_(), q_(), c_() {} void operator ()( double sample ) { double const delta = sample - m_; m_ += delta / ++c_; q_ += delta * ( sample - m_ ); } double sample_variance() const { return (c_ > 1u) ? (q_ / (c_ - 1)) : 0; } double standard_variance() const { return c ? (q_ / c_) : 0; } double sample_stddev() const { return std::sqrt(sample_variance()); } double standard_stddev() const { return std::sqrt(standard_variance()); } double mean() const { return m_; } unsigned long count() const { return c_; } double variance() const {return sample_variance(); } double stddev() const { return sample_stddev(); } double operator ()() const { return stddev(); } }; Then your code would use this function object with std::for_each. It should work with anything that makes iterators, not just circular_buffer. If you're going to take the average from several buffers, make sure to get your function object to assigned the value of the return value of for_each, so the averaging data is carried over. Daryle W.
participants (2)
-
Daryle Walker
-
Ted Byers