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