blob: b121d47e3e914bc7cf6c7afda5d961a565290270 [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
8template <typename VType, typename NumType>
9class Stat1;
10
11template <typename VType, typename NumType>
12class Stat1MinMax;
13
14typedef Stat1<float, float> Stat1_f;
15typedef Stat1<double, double> Stat1_d;
16typedef Stat1MinMax<float, float> Stat1MinMax_f;
17typedef Stat1MinMax<double, double> Stat1MinMax_d;
18
19template <typename VType> class Vector2;
20template <typename VType> class Vector3;
21template <typename VType> class Vector4;
22
23template <typename VType, typename NumType>
24class Stat1 {
25 public:
26 typedef Stat1<VType, NumType> Self;
27
28 Stat1() {
29 Clear();
30 }
31 void Clear() {
32 numsamples_ = NumType();
33 sum_squares_ = sum_ = VType();
34 }
35 // Create a sample of value dat and weight 1
36 explicit Stat1(const VType &dat) {
37 sum_ = dat;
38 sum_squares_ = Sqr(dat);
39 numsamples_ = 1;
40 }
41 // Create statistics for all the samples between begin (included)
42 // and end(excluded)
43 explicit Stat1(const VType *begin, const VType *end) {
44 Clear();
45 for ( const VType *item = begin; item < end; ++item ) {
46 (*this) += Stat1(*item);
47 }
48 }
49 // Create a sample of value dat and weight w
50 Stat1(const VType &dat, const NumType &w) {
51 sum_ = w * dat;
52 sum_squares_ = w * Sqr(dat);
53 numsamples_ = w;
54 }
55 // Copy operator
56 Stat1(const Self &stat) {
57 sum_ = stat.sum_;
58 sum_squares_ = stat.sum_squares_;
59 numsamples_ = stat.numsamples_;
60 }
61
62 inline Self &operator =(const Self &stat) {
63 sum_ = stat.sum_;
64 sum_squares_ = stat.sum_squares_;
65 numsamples_ = stat.numsamples_;
66 return (*this);
67 }
68 // Merge statistics from two sample sets.
69 inline Self &operator +=(const Self &stat) {
70 sum_ += stat.sum_;
71 sum_squares_+= stat.sum_squares_;
72 numsamples_ += stat.numsamples_;
73 return (*this);
74 }
75 // The operation opposite to +=
76 inline Self &operator -=(const Self &stat) {
77 sum_ -= stat.sum_;
78 sum_squares_-= stat.sum_squares_;
79 numsamples_ -= stat.numsamples_;
80 return (*this);
81 }
82 // Multiply the weight of the set of samples by a factor k
83 inline Self &operator *=(const VType &k) {
84 sum_ *= k;
85 sum_squares_*= k;
86 numsamples_ *= k;
87 return (*this);
88 }
89 // Merge statistics from two sample sets.
90 inline Self operator + (const Self &stat) const {
91 return Self(*this) += stat;
92 }
93 // The operation opposite to +
94 inline Self operator - (const Self &stat) const {
95 return Self(*this) -= stat;
96 }
97 // Multiply the weight of the set of samples by a factor k
98 inline Self operator * (const VType &k) const {
99 return Self(*this) *= k;
100 }
101 // Return the total weight of this sample set
102 NumType NumSamples() const {
103 return numsamples_;
104 }
105 // Return the sum of this sample set
106 VType Sum() const {
107 return sum_;
108 }
109 // Return the mean of this sample set
110 VType Mean() const {
111 if (numsamples_ == 0) return VType();
112 return sum_ * (1.0 / numsamples_);
113 }
114 // 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_);
121 *stddev = Sqrt(avg_squares - Sqr(mean));
122 }
123 return mean;
124 }
125 // Return the standard deviation of the sample set
126 VType StdDev() const {
127 if (numsamples_ == 0) return VType();
128 VType mean = Mean();
129 VType avg_squares = sum_squares_ * (1.0 / numsamples_);
130 return Sqrt(avg_squares - Sqr(mean));
131 }
132 private:
133 // Let i be the index of the samples provided (using +=)
134 // and weight[i],value[i] be the data of sample #i
135 // then the variables have the following meaning:
136 NumType numsamples_; // sum of weight[i];
137 VType sum_; // sum of weight[i]*value[i];
138 VType sum_squares_; // sum of weight[i]*value[i]^2;
139
140 // Template function used to square a number.
141 // For a vector we square all components
142 template <typename SType>
143 static inline SType Sqr(const SType &dat) {
144 return dat * dat;
145 }
146 template <typename SType>
147 static inline Vector2<SType> Sqr(const Vector2<SType> &dat) {
148 return dat.MulComponents(dat);
149 }
150 template <typename SType>
151 static inline Vector3<SType> Sqr(const Vector3<SType> &dat) {
152 return dat.MulComponents(dat);
153 }
154 template <typename SType>
155 static inline Vector4<SType> Sqr(const Vector4<SType> &dat) {
156 return dat.MulComponents(dat);
157 }
158
159 // Template function used to take the square root of a number.
160 // For a vector we square all components
161 template <typename SType>
162 static inline SType Sqrt(const SType &dat) {
163 // Avoid NaN due to imprecision in the calculations
164 if ( dat < 0 )
165 return 0;
166 return sqrt(dat);
167 }
168 template <typename SType>
169 static inline Vector2<SType> Sqrt(const Vector2<SType> &dat) {
170 // Avoid NaN due to imprecision in the calculations
171 return Max(dat, Vector2<SType>()).Sqrt();
172 }
173 template <typename SType>
174 static inline Vector3<SType> Sqrt(const Vector3<SType> &dat) {
175 // Avoid NaN due to imprecision in the calculations
176 return Max(dat, Vector3<SType>()).Sqrt();
177 }
178 template <typename SType>
179 static inline Vector4<SType> Sqrt(const Vector4<SType> &dat) {
180 // Avoid NaN due to imprecision in the calculations
181 return Max(dat, Vector4<SType>()).Sqrt();
182 }
183};
184
185// Useful printing function
186template <typename VType, typename NumType>
187inline std::ostream& operator<<(std::ostream& out,
188 const Stat1<VType, NumType>& s) {
189 out << "{ avg = " << s.Mean()
190 << " std = " << s.StdDev()
191 << " nsamples = " << s.NumSamples() << "}";
192 return out;
193}
194
195
196// Stat1MinMax: same as Stat1, but it also
197// keeps the Min and Max values; the "-"
198// operator is disabled because it cannot be implemented
199// efficiently
200template <typename VType, typename NumType>
201class Stat1MinMax : public Stat1<VType, NumType> {
202 public:
203 typedef Stat1MinMax<VType, NumType> Self;
204
205 Stat1MinMax() {
206 Clear();
207 }
208 void Clear() {
209 Stat1<VType, NumType>::Clear();
210 if (std::numeric_limits<VType>::has_infinity) {
211 min_ = std::numeric_limits<VType>::infinity();
212 max_ = -std::numeric_limits<VType>::infinity();
213 } else {
214 min_ = std::numeric_limits<VType>::max();
215 max_ = std::numeric_limits<VType>::min();
216 }
217 }
218 // Create a sample of value dat and weight 1
219 explicit Stat1MinMax(const VType &dat) : Stat1<VType, NumType>(dat) {
220 max_ = dat;
221 min_ = dat;
222 }
223 // Create statistics for all the samples between begin (included)
224 // and end(excluded)
225 explicit Stat1MinMax(const VType *begin, const VType *end) {
226 Clear();
227 for ( const VType *item = begin; item < end; ++item ) {
228 (*this) += Stat1MinMax(*item);
229 }
230 }
231 // Create a sample of value dat and weight w
232 Stat1MinMax(const VType &dat, const NumType &w)
233 : Stat1<VType, NumType>(dat, w) {
234 max_ = dat;
235 min_ = dat;
236 }
237 // Copy operator
238 Stat1MinMax(const Self &stat) : Stat1<VType, NumType>(stat) {
239 max_ = stat.max_;
240 min_ = stat.min_;
241 }
242 inline Self &operator =(const Self &stat) {
243 this->Stat1<VType, NumType>::operator=(stat);
244 max_ = stat.max_;
245 min_ = stat.min_;
246 return (*this);
247 }
248 // Merge statistics from two sample sets.
249 inline Self &operator +=(const Self &stat) {
250 this->Stat1<VType, NumType>::operator+=(stat);
251 if (stat.max_ > max_) max_ = stat.max_;
252 if (stat.min_ < min_) min_ = stat.min_;
253 return (*this);
254 }
255 // Multiply the weight of the set of samples by a factor k
256 inline Self &operator *=(const VType &stat) {
257 this->Stat1<VType, NumType>::operator*=(stat);
258 return (*this);
259 }
260 // Merge statistics from two sample sets.
261 inline Self operator + (const Self &stat) const {
262 return Self(*this) += stat;
263 }
264 // Multiply the weight of the set of samples by a factor k
265 inline Self operator * (const VType &k) const {
266 return Self(*this) *= k;
267 }
268 private:
269 // The - operation makes no sense with Min/Max
270 // unless we keep the full list of values (but we don't)
271 // make it private, and let it undefined so nobody can call it
272 Self &operator -=(const Self &stat); // senseless. let it undefined.
273
274 // The operation opposite to -
275 Self operator - (const Self &stat) const; // senseless. let it undefined.
276
277 public:
278 // Return the maximal value in this sample set
279 VType Max() const {
280 return max_;
281 }
282 // Return the minimal value in this sample set
283 VType Min() const {
284 return min_;
285 }
286 private:
287 // Let i be the index of the samples provided (using +=)
288 // and weight[i],value[i] be the data of sample #i
289 // then the variables have the following meaning:
290 VType max_; // max of value[i]
291 VType min_; // min of value[i]
292};
293
294// Useful printing function
295template <typename VType, typename NumType>
296inline std::ostream& operator <<(std::ostream& out,
297 const Stat1MinMax<VType, NumType>& s) {
298 out << "{ avg = " << s.Mean()
299 << " std = " << s.StdDev()
300 << " nsamples = " << s.NumSamples()
301 << " min = " << s.Min()
302 << " max = " << s.Max() << "}";
303 return out;
304}
305
306#endif // BENCHMARK_STAT_H_