blob: b556309ebfc75db8b30d571ac11be748e1101202 [file] [log] [blame]
Dominic Hamon403f3542013-12-18 16:55:45 -08001#ifndef BENCHMARK_STAT_H_
2#define BENCHMARK_STAT_H_
3
4#include <math.h>
5#include <iostream>
6#include <limits>
7
Dominic Hamone390e4e2013-12-19 16:18:09 -08008namespace benchmark {
Dominic Hamon403f3542013-12-18 16:55:45 -08009template <typename VType, typename NumType>
10class Stat1;
11
12template <typename VType, typename NumType>
13class Stat1MinMax;
14
Dominic Hamon4ce184d2014-01-09 12:12:11 -080015typedef Stat1<float, float> Stat1_f;
Dominic Hamon403f3542013-12-18 16:55:45 -080016typedef Stat1<double, double> Stat1_d;
Dominic Hamon4ce184d2014-01-09 12:12:11 -080017typedef Stat1MinMax<float, float> Stat1MinMax_f;
Dominic Hamon403f3542013-12-18 16:55:45 -080018typedef Stat1MinMax<double, double> Stat1MinMax_d;
19
Dominic Hamon4ce184d2014-01-09 12:12:11 -080020template <typename VType>
21class Vector2;
22template <typename VType>
23class Vector3;
24template <typename VType>
25class Vector4;
Dominic Hamon403f3542013-12-18 16:55:45 -080026
27template <typename VType, typename NumType>
28class Stat1 {
29 public:
30 typedef Stat1<VType, NumType> Self;
31
Dominic Hamon4ce184d2014-01-09 12:12:11 -080032 Stat1() { Clear(); }
Dominic Hamon403f3542013-12-18 16:55:45 -080033 // Create a sample of value dat and weight 1
34 explicit Stat1(const VType &dat) {
35 sum_ = dat;
36 sum_squares_ = Sqr(dat);
37 numsamples_ = 1;
38 }
39 // Create statistics for all the samples between begin (included)
40 // and end(excluded)
41 explicit Stat1(const VType *begin, const VType *end) {
42 Clear();
Dominic Hamon4ce184d2014-01-09 12:12:11 -080043 for (const VType *item = begin; item < end; ++item) {
Dominic Hamon403f3542013-12-18 16:55:45 -080044 (*this) += Stat1(*item);
45 }
46 }
47 // Create a sample of value dat and weight w
48 Stat1(const VType &dat, const NumType &w) {
49 sum_ = w * dat;
50 sum_squares_ = w * Sqr(dat);
51 numsamples_ = w;
52 }
53 // Copy operator
54 Stat1(const Self &stat) {
55 sum_ = stat.sum_;
56 sum_squares_ = stat.sum_squares_;
57 numsamples_ = stat.numsamples_;
58 }
59
Dominic Hamon4ce184d2014-01-09 12:12:11 -080060 void Clear() {
61 numsamples_ = NumType();
62 sum_squares_ = sum_ = VType();
63 }
64
Dominic Hamon5a71bd62014-01-09 12:19:02 -080065 Self &operator=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -080066 sum_ = stat.sum_;
67 sum_squares_ = stat.sum_squares_;
68 numsamples_ = stat.numsamples_;
69 return (*this);
70 }
71 // Merge statistics from two sample sets.
Dominic Hamon5a71bd62014-01-09 12:19:02 -080072 Self &operator+=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -080073 sum_ += stat.sum_;
Dominic Hamon4ce184d2014-01-09 12:12:11 -080074 sum_squares_ += stat.sum_squares_;
Dominic Hamon403f3542013-12-18 16:55:45 -080075 numsamples_ += stat.numsamples_;
76 return (*this);
77 }
78 // The operation opposite to +=
Dominic Hamon5a71bd62014-01-09 12:19:02 -080079 Self &operator-=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -080080 sum_ -= stat.sum_;
Dominic Hamon4ce184d2014-01-09 12:12:11 -080081 sum_squares_ -= stat.sum_squares_;
Dominic Hamon403f3542013-12-18 16:55:45 -080082 numsamples_ -= stat.numsamples_;
83 return (*this);
84 }
85 // Multiply the weight of the set of samples by a factor k
Dominic Hamon5a71bd62014-01-09 12:19:02 -080086 Self &operator*=(const VType &k) {
Dominic Hamon403f3542013-12-18 16:55:45 -080087 sum_ *= k;
Dominic Hamon4ce184d2014-01-09 12:12:11 -080088 sum_squares_ *= k;
Dominic Hamon403f3542013-12-18 16:55:45 -080089 numsamples_ *= k;
90 return (*this);
91 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -080092
Dominic Hamon403f3542013-12-18 16:55:45 -080093 // Merge statistics from two sample sets.
Dominic Hamon5a71bd62014-01-09 12:19:02 -080094 Self operator+(const Self &stat) const { return Self(*this) += stat; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -080095
Dominic Hamon403f3542013-12-18 16:55:45 -080096 // The operation opposite to +
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 // Multiply the weight of the set of samples by a factor k
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800100 Self operator*(const VType &k) const { return Self(*this) *= k; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800101
Dominic Hamon403f3542013-12-18 16:55:45 -0800102 // Return the total weight of this sample set
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800103 NumType numSamples() const { return numsamples_; }
104
Dominic Hamon403f3542013-12-18 16:55:45 -0800105 // Return the sum of this sample set
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800106 VType sum() const { return sum_; }
107
Dominic Hamon403f3542013-12-18 16:55:45 -0800108 // Return the mean of this sample set
109 VType Mean() const {
110 if (numsamples_ == 0) return VType();
111 return sum_ * (1.0 / numsamples_);
112 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800113
Dominic Hamon403f3542013-12-18 16:55:45 -0800114 // Return the mean of this sample set and compute the standard deviation at
115 // the same time.
116 VType Mean(VType *stddev) const {
117 if (numsamples_ == 0) return VType();
118 VType mean = sum_ * (1.0 / numsamples_);
119 if (stddev) {
120 VType avg_squares = sum_squares_ * (1.0 / numsamples_);
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800121 *stddev = Sqrt(avg_squares - Sqr(mean));
Dominic Hamon403f3542013-12-18 16:55:45 -0800122 }
123 return mean;
124 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800125
Dominic Hamon403f3542013-12-18 16:55:45 -0800126 // Return the standard deviation of the sample set
127 VType StdDev() const {
128 if (numsamples_ == 0) return VType();
129 VType mean = Mean();
130 VType avg_squares = sum_squares_ * (1.0 / numsamples_);
131 return Sqrt(avg_squares - Sqr(mean));
132 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800133
Dominic Hamon403f3542013-12-18 16:55:45 -0800134 private:
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800135 // Let i be the index of the samples provided (using +=)
136 // and weight[i],value[i] be the data of sample #i
137 // then the variables have the following meaning:
Dominic Hamon403f3542013-12-18 16:55:45 -0800138 NumType numsamples_; // sum of weight[i];
139 VType sum_; // sum of weight[i]*value[i];
140 VType sum_squares_; // sum of weight[i]*value[i]^2;
141
142 // Template function used to square a number.
143 // For a vector we square all components
144 template <typename SType>
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800145 static inline SType Sqr(const SType &dat) {
146 return dat * dat;
147 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800148
Dominic Hamon403f3542013-12-18 16:55:45 -0800149 template <typename SType>
150 static inline Vector2<SType> Sqr(const Vector2<SType> &dat) {
151 return dat.MulComponents(dat);
152 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800153
Dominic Hamon403f3542013-12-18 16:55:45 -0800154 template <typename SType>
155 static inline Vector3<SType> Sqr(const Vector3<SType> &dat) {
156 return dat.MulComponents(dat);
157 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800158
Dominic Hamon403f3542013-12-18 16:55:45 -0800159 template <typename SType>
160 static inline Vector4<SType> Sqr(const Vector4<SType> &dat) {
161 return dat.MulComponents(dat);
162 }
163
164 // Template function used to take the square root of a number.
165 // For a vector we square all components
166 template <typename SType>
167 static inline SType Sqrt(const SType &dat) {
168 // Avoid NaN due to imprecision in the calculations
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800169 if (dat < 0) return 0;
Dominic Hamon403f3542013-12-18 16:55:45 -0800170 return sqrt(dat);
171 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800172
Dominic Hamon403f3542013-12-18 16:55:45 -0800173 template <typename SType>
174 static inline Vector2<SType> Sqrt(const Vector2<SType> &dat) {
175 // Avoid NaN due to imprecision in the calculations
176 return Max(dat, Vector2<SType>()).Sqrt();
177 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800178
Dominic Hamon403f3542013-12-18 16:55:45 -0800179 template <typename SType>
180 static inline Vector3<SType> Sqrt(const Vector3<SType> &dat) {
181 // Avoid NaN due to imprecision in the calculations
182 return Max(dat, Vector3<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 Vector4<SType> Sqrt(const Vector4<SType> &dat) {
187 // Avoid NaN due to imprecision in the calculations
188 return Max(dat, Vector4<SType>()).Sqrt();
189 }
190};
191
192// Useful printing function
193template <typename VType, typename NumType>
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800194std::ostream &operator<<(std::ostream &out, const Stat1<VType, NumType> &s) {
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800195 out << "{ avg = " << s.Mean() << " std = " << s.StdDev()
Dominic Hamon403f3542013-12-18 16:55:45 -0800196 << " nsamples = " << s.NumSamples() << "}";
197 return out;
198}
199
Dominic Hamon403f3542013-12-18 16:55:45 -0800200// Stat1MinMax: same as Stat1, but it also
201// keeps the Min and Max values; the "-"
202// operator is disabled because it cannot be implemented
203// efficiently
204template <typename VType, typename NumType>
205class Stat1MinMax : public Stat1<VType, NumType> {
206 public:
207 typedef Stat1MinMax<VType, NumType> Self;
208
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800209 Stat1MinMax() { Clear(); }
210 // Create a sample of value dat and weight 1
211 explicit Stat1MinMax(const VType &dat) : Stat1<VType, NumType>(dat) {
212 max_ = dat;
213 min_ = dat;
Dominic Hamon403f3542013-12-18 16:55:45 -0800214 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800215 // Create statistics for all the samples between begin (included)
216 // and end(excluded)
217 explicit Stat1MinMax(const VType *begin, const VType *end) {
218 Clear();
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800219 for (const VType *item = begin; item < end; ++item) {
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800220 (*this) += Stat1MinMax(*item);
221 }
222 }
223 // Create a sample of value dat and weight w
224 Stat1MinMax(const VType &dat, const NumType &w)
225 : Stat1<VType, NumType>(dat, w) {
226 max_ = dat;
227 min_ = dat;
228 }
229 // Copy operator
230 Stat1MinMax(const Self &stat) : Stat1<VType, NumType>(stat) {
231 max_ = stat.max_;
232 min_ = stat.min_;
233 }
234
Dominic Hamon403f3542013-12-18 16:55:45 -0800235 void Clear() {
236 Stat1<VType, NumType>::Clear();
237 if (std::numeric_limits<VType>::has_infinity) {
238 min_ = std::numeric_limits<VType>::infinity();
239 max_ = -std::numeric_limits<VType>::infinity();
240 } else {
241 min_ = std::numeric_limits<VType>::max();
242 max_ = std::numeric_limits<VType>::min();
243 }
244 }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800245
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800246 Self &operator=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -0800247 this->Stat1<VType, NumType>::operator=(stat);
248 max_ = stat.max_;
249 min_ = stat.min_;
250 return (*this);
251 }
252 // Merge statistics from two sample sets.
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800253 Self &operator+=(const Self &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -0800254 this->Stat1<VType, NumType>::operator+=(stat);
255 if (stat.max_ > max_) max_ = stat.max_;
256 if (stat.min_ < min_) min_ = stat.min_;
257 return (*this);
258 }
259 // Multiply the weight of the set of samples by a factor k
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800260 Self &operator*=(const VType &stat) {
Dominic Hamon403f3542013-12-18 16:55:45 -0800261 this->Stat1<VType, NumType>::operator*=(stat);
262 return (*this);
263 }
264 // Merge statistics from two sample sets.
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800265 Self operator+(const Self &stat) const { return Self(*this) += stat; }
Dominic Hamon403f3542013-12-18 16:55:45 -0800266 // Multiply the weight of the set of samples by a factor k
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800267 Self operator*(const VType &k) const { return Self(*this) *= k; }
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800268
269 // Return the maximal value in this sample set
270 VType max() const { return max_; }
271 // Return the minimal value in this sample set
272 VType min() const { return min_; }
273
Dominic Hamon403f3542013-12-18 16:55:45 -0800274 private:
275 // The - operation makes no sense with Min/Max
276 // unless we keep the full list of values (but we don't)
277 // make it private, and let it undefined so nobody can call it
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800278 Self &operator-=(const Self &stat); // senseless. let it undefined.
Dominic Hamon403f3542013-12-18 16:55:45 -0800279
280 // The operation opposite to -
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800281 Self operator-(const Self &stat) const; // senseless. let it undefined.
Dominic Hamon403f3542013-12-18 16:55:45 -0800282
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800283 // Let i be the index of the samples provided (using +=)
284 // and weight[i],value[i] be the data of sample #i
285 // then the variables have the following meaning:
286 VType max_; // max of value[i]
287 VType min_; // min of value[i]
Dominic Hamon403f3542013-12-18 16:55:45 -0800288};
289
290// Useful printing function
291template <typename VType, typename NumType>
Dominic Hamon5a71bd62014-01-09 12:19:02 -0800292std::ostream &operator<<(std::ostream &out,
293 const Stat1MinMax<VType, NumType> &s) {
Dominic Hamon4ce184d2014-01-09 12:12:11 -0800294 out << "{ avg = " << s.Mean() << " std = " << s.StdDev()
295 << " nsamples = " << s.NumSamples() << " min = " << s.Min()
Dominic Hamon403f3542013-12-18 16:55:45 -0800296 << " max = " << s.Max() << "}";
297 return out;
298}
Dominic Hamone390e4e2013-12-19 16:18:09 -0800299} // end namespace benchmark
Dominic Hamon403f3542013-12-18 16:55:45 -0800300
301#endif // BENCHMARK_STAT_H_