#ifndef BENCHMARK_STAT_H_ #define BENCHMARK_STAT_H_ #include #include #include template class Stat1; template class Stat1MinMax; typedef Stat1 Stat1_f; typedef Stat1 Stat1_d; typedef Stat1MinMax Stat1MinMax_f; typedef Stat1MinMax Stat1MinMax_d; template class Vector2; template class Vector3; template class Vector4; template class Stat1 { public: typedef Stat1 Self; Stat1() { Clear(); } void Clear() { numsamples_ = NumType(); sum_squares_ = sum_ = VType(); } // Create a sample of value dat and weight 1 explicit Stat1(const VType &dat) { sum_ = dat; sum_squares_ = Sqr(dat); numsamples_ = 1; } // Create statistics for all the samples between begin (included) // and end(excluded) explicit Stat1(const VType *begin, const VType *end) { Clear(); for ( const VType *item = begin; item < end; ++item ) { (*this) += Stat1(*item); } } // Create a sample of value dat and weight w Stat1(const VType &dat, const NumType &w) { sum_ = w * dat; sum_squares_ = w * Sqr(dat); numsamples_ = w; } // Copy operator Stat1(const Self &stat) { sum_ = stat.sum_; sum_squares_ = stat.sum_squares_; numsamples_ = stat.numsamples_; } inline Self &operator =(const Self &stat) { sum_ = stat.sum_; sum_squares_ = stat.sum_squares_; numsamples_ = stat.numsamples_; return (*this); } // Merge statistics from two sample sets. inline Self &operator +=(const Self &stat) { sum_ += stat.sum_; sum_squares_+= stat.sum_squares_; numsamples_ += stat.numsamples_; return (*this); } // The operation opposite to += inline Self &operator -=(const Self &stat) { sum_ -= stat.sum_; sum_squares_-= stat.sum_squares_; numsamples_ -= stat.numsamples_; return (*this); } // Multiply the weight of the set of samples by a factor k inline Self &operator *=(const VType &k) { sum_ *= k; sum_squares_*= k; numsamples_ *= k; return (*this); } // Merge statistics from two sample sets. inline Self operator + (const Self &stat) const { return Self(*this) += stat; } // The operation opposite to + inline Self operator - (const Self &stat) const { return Self(*this) -= stat; } // Multiply the weight of the set of samples by a factor k inline Self operator * (const VType &k) const { return Self(*this) *= k; } // Return the total weight of this sample set NumType NumSamples() const { return numsamples_; } // Return the sum of this sample set VType Sum() const { return sum_; } // Return the mean of this sample set VType Mean() const { if (numsamples_ == 0) return VType(); return sum_ * (1.0 / numsamples_); } // Return the mean of this sample set and compute the standard deviation at // the same time. VType Mean(VType *stddev) const { if (numsamples_ == 0) return VType(); VType mean = sum_ * (1.0 / numsamples_); if (stddev) { VType avg_squares = sum_squares_ * (1.0 / numsamples_); *stddev = Sqrt(avg_squares - Sqr(mean)); } return mean; } // Return the standard deviation of the sample set VType StdDev() const { if (numsamples_ == 0) return VType(); VType mean = Mean(); VType avg_squares = sum_squares_ * (1.0 / numsamples_); return Sqrt(avg_squares - Sqr(mean)); } private: // Let i be the index of the samples provided (using +=) // and weight[i],value[i] be the data of sample #i // then the variables have the following meaning: NumType numsamples_; // sum of weight[i]; VType sum_; // sum of weight[i]*value[i]; VType sum_squares_; // sum of weight[i]*value[i]^2; // Template function used to square a number. // For a vector we square all components template static inline SType Sqr(const SType &dat) { return dat * dat; } template static inline Vector2 Sqr(const Vector2 &dat) { return dat.MulComponents(dat); } template static inline Vector3 Sqr(const Vector3 &dat) { return dat.MulComponents(dat); } template static inline Vector4 Sqr(const Vector4 &dat) { return dat.MulComponents(dat); } // Template function used to take the square root of a number. // For a vector we square all components template static inline SType Sqrt(const SType &dat) { // Avoid NaN due to imprecision in the calculations if ( dat < 0 ) return 0; return sqrt(dat); } template static inline Vector2 Sqrt(const Vector2 &dat) { // Avoid NaN due to imprecision in the calculations return Max(dat, Vector2()).Sqrt(); } template static inline Vector3 Sqrt(const Vector3 &dat) { // Avoid NaN due to imprecision in the calculations return Max(dat, Vector3()).Sqrt(); } template static inline Vector4 Sqrt(const Vector4 &dat) { // Avoid NaN due to imprecision in the calculations return Max(dat, Vector4()).Sqrt(); } }; // Useful printing function template inline std::ostream& operator<<(std::ostream& out, const Stat1& s) { out << "{ avg = " << s.Mean() << " std = " << s.StdDev() << " nsamples = " << s.NumSamples() << "}"; return out; } // Stat1MinMax: same as Stat1, but it also // keeps the Min and Max values; the "-" // operator is disabled because it cannot be implemented // efficiently template class Stat1MinMax : public Stat1 { public: typedef Stat1MinMax Self; Stat1MinMax() { Clear(); } void Clear() { Stat1::Clear(); if (std::numeric_limits::has_infinity) { min_ = std::numeric_limits::infinity(); max_ = -std::numeric_limits::infinity(); } else { min_ = std::numeric_limits::max(); max_ = std::numeric_limits::min(); } } // Create a sample of value dat and weight 1 explicit Stat1MinMax(const VType &dat) : Stat1(dat) { max_ = dat; min_ = dat; } // Create statistics for all the samples between begin (included) // and end(excluded) explicit Stat1MinMax(const VType *begin, const VType *end) { Clear(); for ( const VType *item = begin; item < end; ++item ) { (*this) += Stat1MinMax(*item); } } // Create a sample of value dat and weight w Stat1MinMax(const VType &dat, const NumType &w) : Stat1(dat, w) { max_ = dat; min_ = dat; } // Copy operator Stat1MinMax(const Self &stat) : Stat1(stat) { max_ = stat.max_; min_ = stat.min_; } inline Self &operator =(const Self &stat) { this->Stat1::operator=(stat); max_ = stat.max_; min_ = stat.min_; return (*this); } // Merge statistics from two sample sets. inline Self &operator +=(const Self &stat) { this->Stat1::operator+=(stat); if (stat.max_ > max_) max_ = stat.max_; if (stat.min_ < min_) min_ = stat.min_; return (*this); } // Multiply the weight of the set of samples by a factor k inline Self &operator *=(const VType &stat) { this->Stat1::operator*=(stat); return (*this); } // Merge statistics from two sample sets. inline Self operator + (const Self &stat) const { return Self(*this) += stat; } // Multiply the weight of the set of samples by a factor k inline Self operator * (const VType &k) const { return Self(*this) *= k; } private: // The - operation makes no sense with Min/Max // unless we keep the full list of values (but we don't) // make it private, and let it undefined so nobody can call it Self &operator -=(const Self &stat); // senseless. let it undefined. // The operation opposite to - Self operator - (const Self &stat) const; // senseless. let it undefined. public: // Return the maximal value in this sample set VType Max() const { return max_; } // Return the minimal value in this sample set VType Min() const { return min_; } private: // Let i be the index of the samples provided (using +=) // and weight[i],value[i] be the data of sample #i // then the variables have the following meaning: VType max_; // max of value[i] VType min_; // min of value[i] }; // Useful printing function template inline std::ostream& operator <<(std::ostream& out, const Stat1MinMax& s) { out << "{ avg = " << s.Mean() << " std = " << s.StdDev() << " nsamples = " << s.NumSamples() << " min = " << s.Min() << " max = " << s.Max() << "}"; return out; } #endif // BENCHMARK_STAT_H_