forked from travisdowns/uarch-bench
-
Notifications
You must be signed in to change notification settings - Fork 0
/
stats.hpp
128 lines (106 loc) · 3.58 KB
/
stats.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
* Really simple descriptive stats.
*
* stats.hpp
*/
#ifndef STATS_HPP_
#define STATS_HPP_
#include <string>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <limits>
#include <iterator>
#include <functional>
#include <vector>
namespace Stats {
class DescriptiveStats {
double min_, max_, avg_, median_;
size_t count_;
public:
DescriptiveStats(double min, double max, double avg, double median, size_t count) :
min_(min), max_(max), avg_(avg), median_(median), count_(count) {}
double getAvg() const {
return avg_;
}
size_t getCount() const {
return count_;
}
double getMax() const {
return max_;
}
double getMin() const {
return min_;
}
double getMedian() const {
return median_;
}
/*
* Return a string with the values of min/median/avg/max at the specified precision.
* Note that the count is not included.
*/
std::string getString4(int width, int precision) const {
std::ostringstream os;
os << std::fixed << std::setprecision(precision) <<
std::setw(width) << getMin() << "/" <<
std::setw(width) << getMedian() << "/" <<
std::setw(width) << getAvg() << "/" <<
std::setw(width) << getMax();
return os.str();
}
};
template <typename iter_type, typename LESS>
typename std::iterator_traits<iter_type>::value_type median(iter_type first, iter_type last, LESS comp) {
if (first == last) {
throw std::logic_error("can't get median of empty range");
}
using T = typename std::iterator_traits<iter_type>::value_type;
std::vector<T> copy(first, last);
std::sort(copy.begin(), copy.end(), comp);
size_t sz = copy.size(), half_sz = sz / 2;
return sz % 2 ? copy[half_sz] : (copy[half_sz - 1] + copy[half_sz]) / 2;
}
/**
* Like median above, except that with an even number of elements, where there are two middle elements with
* equal claim to the throne, the lesser of the two elements is returned rather trying to average them. This
* method is more generally applicable since it always returns on of the elements of the input range directly
* and doesn't require the elements to expose the operations required to calculate an average.
*/
template <typename iter_type, typename LESS>
typename std::iterator_traits<iter_type>::value_type medianf(iter_type first, iter_type last, LESS comp) {
if (first == last) {
throw std::logic_error("can't get median of empty range");
}
using T = typename std::iterator_traits<iter_type>::value_type;
std::vector<T> copy(first, last);
std::sort(copy.begin(), copy.end(), comp);
assert(!copy.empty());
return copy[(copy.size() - 1) / 2];
}
template <typename iter_type>
typename std::iterator_traits<iter_type>::value_type median(iter_type first, iter_type last) {
auto p = std::less<typename std::iterator_traits<iter_type>::value_type>();
return Stats::median<iter_type>(first, last, p);
}
template <typename iter_type>
DescriptiveStats get_stats(iter_type first, iter_type last) {
using dlimits = std::numeric_limits<double>;
double min = dlimits::max(), max = dlimits::min(), total = 0;
size_t count = 0;
for (iter_type itr = first; itr != last; itr++) {
auto val = *itr;
double vald = val;
if (vald < min) min = vald;
if (vald > max) max = vald;
total += vald;
count++;
}
return DescriptiveStats(min, max, total / count, median(first, last), count);
}
inline std::ostream& operator<<(std::ostream &os, const DescriptiveStats &stats) {
os << "min=" << stats.getMin() << ", median=" << stats.getMedian() << ", avg=" << stats.getAvg()
<< ", max=" << stats.getMax() << ", n=" << stats.getCount();
return os;
}
} // namepsace Stats
#endif /* STATS_HPP_ */