blob: c4ecfe8e0442d615839abdc026290fd8cfb1a588 [file] [log] [blame]
Dominic Hamon403f3542013-12-18 16:55:45 -08001#ifndef BENCHMARK_STAT_H_
2#define BENCHMARK_STAT_H_
3
Eric Fiseliera187aa02015-03-06 17:01:05 -05004#include <cmath>
Dominic Hamon403f3542013-12-18 16:55:45 -08005#include <limits>
Eric Fiselier66bf7c82015-03-12 20:27:29 -04006#include <ostream>
7#include <type_traits>
8
Dominic Hamon403f3542013-12-18 16:55:45 -08009
Dominic Hamone390e4e2013-12-19 16:18:09 -080010namespace benchmark {
Eric Fiseliera187aa02015-03-06 17:01:05 -050011
Dominic Hamon403f3542013-12-18 16:55:45 -080012template <typename VType, typename NumType>
13class Stat1;
14
15template <typename VType, typename NumType>
16class Stat1MinMax;
17
Eric Fiselier66bf7c82015-03-12 20:27:29 -040018typedef Stat1<float, int64_t> Stat1_f;
19typedef Stat1<double, int64_t> Stat1_d;
20typedef Stat1MinMax<float, int64_t> Stat1MinMax_f;
21typedef Stat1MinMax<double, int64_t> Stat1MinMax_d;
Dominic Hamon403f3542013-12-18 16:55:45 -080022
Dominic Hamon4ce184d2014-01-09 12:12:11 -080023template <typename VType>
24class Vector2;
25template <typename VType>
26class Vector3;
27template <typename VType>
28class Vector4;
Dominic Hamon403f3542013-12-18 16:55:45 -080029
30template <typename VType, typename NumType>
31class Stat1 {
32 public:
33 typedef Stat1<VType, NumType> Self;
34
Dominic Hamon4ce184d2014-01-09 12:12:11 -080035 Stat1() { Clear(); }
Dominic Hamon403f3542013-12-18 16:55:45 -080036 // Create a sample of value dat and weight 1
37 explicit Stat1(const VType &dat) {
38 sum_ = dat;
39 sum_squares_ = Sqr(dat);
40 numsamples_ = 1;
41 }
42 // Create statistics for all the samples between begin (included)
43 // and end(excluded)
44 explicit Stat1(const VType *begin, const VType *end) {
45 Clear();
Dominic Hamon4ce184d2014-01-09 12:12:11 -080046 for (const VType *item = begin; item < end; ++item) {
Dominic Hamon403f3542013-12-18 16:55:45 -080047 (*this) += Stat1(*item);
48 }
49 }
50 // Create a sample of value dat and weight w
51 Stat1(const VType &dat, const NumType &w) {
52 sum_ = w * dat;
53 sum_squares_ = w * Sqr(dat);
54 numsamples_ = w;
55 }
56 // Copy operator
57 Stat1(const Self &stat) {
58 sum_ = stat.sum_;
59 sum_squares_ = stat.sum_squares_;
60 numsamples_ = stat.numsamples_;
61 }
62
Dominic Hamon4ce184d2014-01-09 12:12:11 -080063 void Clear() {
64 numsamples_ = NumType();
65 sum_squares_ = sum_ = VType();
66 }
67
Dominic Hamon5a71bd62014-01-09 12:19:02 -080068 Self &operator=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -080069 sum_ = stat.sum_;
70 sum_squares_ = stat.sum_squares_;
71 numsamples_ = stat.numsamples_;
72 return (*this);
73 }
74 // Merge statistics from two sample sets.
Dominic Hamon5a71bd62014-01-09 12:19:02 -080075 Self &operator+=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -080076 sum_ += stat.sum_;
Dominic Hamon4ce184d2014-01-09 12:12:11 -080077 sum_squares_ += stat.sum_squares_;
Dominic Hamon403f3542013-12-18 16:55:45 -080078 numsamples_ += stat.numsamples_;
79 return (*this);
80 }
81 // The operation opposite to +=
Dominic Hamon5a71bd62014-01-09 12:19:02 -080082 Self &operator-=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -080083 sum_ -= stat.sum_;
Dominic Hamon4ce184d2014-01-09 12:12:11 -080084 sum_squares_ -= stat.sum_squares_;
Dominic Hamon403f3542013-12-18 16:55:45 -080085 numsamples_ -= stat.numsamples_;
86 return (*this);
87 }
88 // Multiply the weight of the set of samples by a factor k
Dominic Hamon5a71bd62014-01-09 12:19:02 -080089 Self &operator*=(const VType &k) {
Dominic Hamon403f3542013-12-18 16:55:45 -080090 sum_ *= k;
Dominic Hamon4ce184d2014-01-09 12:12:11 -080091 sum_squares_ *= k;
Dominic Hamon403f3542013-12-18 16:55:45 -080092 numsamples_ *= k;
93 return (*this);
94 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -080095
Dominic Hamon403f3542013-12-18 16:55:45 -080096 // Merge statistics from two sample sets.
Dominic Hamon5a71bd62014-01-09 12:19:02 -080097 Self operator+(const Self &stat) const { return Self(*this) += stat; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -080098
Dominic Hamon403f3542013-12-18 16:55:45 -080099 // The operation opposite to +
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800100 Self operator-(const Self &stat) const { return Self(*this) -= stat; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800101
Dominic Hamon403f3542013-12-18 16:55:45 -0800102 // Multiply the weight of the set of samples by a factor k
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800103 Self operator*(const VType &k) const { return Self(*this) *= k; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800104
Dominic Hamon403f3542013-12-18 16:55:45 -0800105 // Return the total weight of this sample set
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800106 NumType numSamples() const { return numsamples_; }
107
Dominic Hamon403f3542013-12-18 16:55:45 -0800108 // Return the sum of this sample set
Eric Fiseliera187aa02015-03-06 17:01:05 -0500109 VType Sum() const { return sum_; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800110
Dominic Hamon403f3542013-12-18 16:55:45 -0800111 // Return the mean of this sample set
112 VType Mean() const {
113 if (numsamples_ == 0) return VType();
114 return sum_ * (1.0 / numsamples_);
115 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800116
Dominic Hamon403f3542013-12-18 16:55:45 -0800117 // Return the mean of this sample set and compute the standard deviation at
118 // the same time.
119 VType Mean(VType *stddev) const {
120 if (numsamples_ == 0) return VType();
121 VType mean = sum_ * (1.0 / numsamples_);
122 if (stddev) {
123 VType avg_squares = sum_squares_ * (1.0 / numsamples_);
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800124 *stddev = Sqrt(avg_squares - Sqr(mean));
Dominic Hamon403f3542013-12-18 16:55:45 -0800125 }
126 return mean;
127 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800128
Dominic Hamon403f3542013-12-18 16:55:45 -0800129 // Return the standard deviation of the sample set
130 VType StdDev() const {
131 if (numsamples_ == 0) return VType();
132 VType mean = Mean();
133 VType avg_squares = sum_squares_ * (1.0 / numsamples_);
134 return Sqrt(avg_squares - Sqr(mean));
135 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800136
Dominic Hamon403f3542013-12-18 16:55:45 -0800137 private:
Eric Fiselier66bf7c82015-03-12 20:27:29 -0400138 static_assert(std::is_integral<NumType>::value &&
139 !std::is_same<NumType, bool>::value,
140 "NumType must be an integral type that is not bool.");
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800141 // Let i be the index of the samples provided (using +=)
142 // and weight[i],value[i] be the data of sample #i
143 // then the variables have the following meaning:
Dominic Hamon403f3542013-12-18 16:55:45 -0800144 NumType numsamples_; // sum of weight[i];
145 VType sum_; // sum of weight[i]*value[i];
146 VType sum_squares_; // sum of weight[i]*value[i]^2;
147
148 // Template function used to square a number.
149 // For a vector we square all components
150 template <typename SType>
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800151 static inline SType Sqr(const SType &dat) {
152 return dat * dat;
153 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800154
Dominic Hamon403f3542013-12-18 16:55:45 -0800155 template <typename SType>
156 static inline Vector2<SType> Sqr(const Vector2<SType> &dat) {
157 return dat.MulComponents(dat);
158 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800159
Dominic Hamon403f3542013-12-18 16:55:45 -0800160 template <typename SType>
161 static inline Vector3<SType> Sqr(const Vector3<SType> &dat) {
162 return dat.MulComponents(dat);
163 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800164
Dominic Hamon403f3542013-12-18 16:55:45 -0800165 template <typename SType>
166 static inline Vector4<SType> Sqr(const Vector4<SType> &dat) {
167 return dat.MulComponents(dat);
168 }
169
170 // Template function used to take the square root of a number.
171 // For a vector we square all components
172 template <typename SType>
173 static inline SType Sqrt(const SType &dat) {
174 // Avoid NaN due to imprecision in the calculations
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800175 if (dat < 0) return 0;
Dominic Hamon403f3542013-12-18 16:55:45 -0800176 return sqrt(dat);
177 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800178
Dominic Hamon403f3542013-12-18 16:55:45 -0800179 template <typename SType>
180 static inline Vector2<SType> Sqrt(const Vector2<SType> &dat) {
181 // Avoid NaN due to imprecision in the calculations
182 return Max(dat, Vector2<SType>()).Sqrt();
183 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800184
Dominic Hamon403f3542013-12-18 16:55:45 -0800185 template <typename SType>
186 static inline Vector3<SType> Sqrt(const Vector3<SType> &dat) {
187 // Avoid NaN due to imprecision in the calculations
188 return Max(dat, Vector3<SType>()).Sqrt();
189 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800190
Dominic Hamon403f3542013-12-18 16:55:45 -0800191 template <typename SType>
192 static inline Vector4<SType> Sqrt(const Vector4<SType> &dat) {
193 // Avoid NaN due to imprecision in the calculations
194 return Max(dat, Vector4<SType>()).Sqrt();
195 }
196};
197
198// Useful printing function
199template <typename VType, typename NumType>
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800200std::ostream &operator<<(std::ostream &out, const Stat1<VType, NumType> &s) {
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800201 out << "{ avg = " << s.Mean() << " std = " << s.StdDev()
Dominic Hamon403f3542013-12-18 16:55:45 -0800202 << " nsamples = " << s.NumSamples() << "}";
203 return out;
204}
205
Dominic Hamon403f3542013-12-18 16:55:45 -0800206// Stat1MinMax: same as Stat1, but it also
207// keeps the Min and Max values; the "-"
208// operator is disabled because it cannot be implemented
209// efficiently
210template <typename VType, typename NumType>
211class Stat1MinMax : public Stat1<VType, NumType> {
212 public:
213 typedef Stat1MinMax<VType, NumType> Self;
214
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800215 Stat1MinMax() { Clear(); }
216 // Create a sample of value dat and weight 1
217 explicit Stat1MinMax(const VType &dat) : Stat1<VType, NumType>(dat) {
218 max_ = dat;
219 min_ = dat;
Dominic Hamon403f3542013-12-18 16:55:45 -0800220 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800221 // Create statistics for all the samples between begin (included)
222 // and end(excluded)
223 explicit Stat1MinMax(const VType *begin, const VType *end) {
224 Clear();
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800225 for (const VType *item = begin; item < end; ++item) {
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800226 (*this) += Stat1MinMax(*item);
227 }
228 }
229 // Create a sample of value dat and weight w
230 Stat1MinMax(const VType &dat, const NumType &w)
231 : Stat1<VType, NumType>(dat, w) {
232 max_ = dat;
233 min_ = dat;
234 }
235 // Copy operator
236 Stat1MinMax(const Self &stat) : Stat1<VType, NumType>(stat) {
237 max_ = stat.max_;
238 min_ = stat.min_;
239 }
240
Dominic Hamon403f3542013-12-18 16:55:45 -0800241 void Clear() {
242 Stat1<VType, NumType>::Clear();
243 if (std::numeric_limits<VType>::has_infinity) {
244 min_ = std::numeric_limits<VType>::infinity();
245 max_ = -std::numeric_limits<VType>::infinity();
246 } else {
247 min_ = std::numeric_limits<VType>::max();
248 max_ = std::numeric_limits<VType>::min();
249 }
250 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800251
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800252 Self &operator=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -0800253 this->Stat1<VType, NumType>::operator=(stat);
254 max_ = stat.max_;
255 min_ = stat.min_;
256 return (*this);
257 }
258 // Merge statistics from two sample sets.
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800259 Self &operator+=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -0800260 this->Stat1<VType, NumType>::operator+=(stat);
261 if (stat.max_ > max_) max_ = stat.max_;
262 if (stat.min_ < min_) min_ = stat.min_;
263 return (*this);
264 }
265 // Multiply the weight of the set of samples by a factor k
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800266 Self &operator*=(const VType &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -0800267 this->Stat1<VType, NumType>::operator*=(stat);
268 return (*this);
269 }
270 // Merge statistics from two sample sets.
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800271 Self operator+(const Self &stat) const { return Self(*this) += stat; }
Dominic Hamon403f3542013-12-18 16:55:45 -0800272 // Multiply the weight of the set of samples by a factor k
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800273 Self operator*(const VType &k) const { return Self(*this) *= k; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800274
275 // Return the maximal value in this sample set
Eric Fiseliera187aa02015-03-06 17:01:05 -0500276 VType Max() const { return max_; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800277 // Return the minimal value in this sample set
Eric Fiseliera187aa02015-03-06 17:01:05 -0500278 VType Min() const { return min_; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800279
Dominic Hamon403f3542013-12-18 16:55:45 -0800280 private:
281 // The - operation makes no sense with Min/Max
282 // unless we keep the full list of values (but we don't)
283 // make it private, and let it undefined so nobody can call it
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800284 Self &operator-=(const Self &stat); // senseless. let it undefined.
Dominic Hamon403f3542013-12-18 16:55:45 -0800285
286 // The operation opposite to -
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800287 Self operator-(const Self &stat) const; // senseless. let it undefined.
Dominic Hamon403f3542013-12-18 16:55:45 -0800288
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800289 // Let i be the index of the samples provided (using +=)
290 // and weight[i],value[i] be the data of sample #i
291 // then the variables have the following meaning:
292 VType max_; // max of value[i]
293 VType min_; // min of value[i]
Dominic Hamon403f3542013-12-18 16:55:45 -0800294};
295
296// Useful printing function
297template <typename VType, typename NumType>
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800298std::ostream &operator<<(std::ostream &out,
299 const Stat1MinMax<VType, NumType> &s) {
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800300 out << "{ avg = " << s.Mean() << " std = " << s.StdDev()
301 << " nsamples = " << s.NumSamples() << " min = " << s.Min()
Dominic Hamon403f3542013-12-18 16:55:45 -0800302 << " max = " << s.Max() << "}";
303 return out;
304}
Dominic Hamone390e4e2013-12-19 16:18:09 -0800305} // end namespace benchmark
Dominic Hamon403f3542013-12-18 16:55:45 -0800306
307#endif // BENCHMARK_STAT_H_