170 lines
5.4 KiB
C++
170 lines
5.4 KiB
C++
#ifndef STATISTICS_H
|
|
#define STATISTICS_H
|
|
|
|
#include <set>
|
|
#include <cstdint>
|
|
#include <sstream>
|
|
#include <cmath>
|
|
|
|
namespace Stats {
|
|
|
|
/**
|
|
* store values here and get statistics about their
|
|
* avg, median, std-dev, etc.
|
|
*/
|
|
template <typename T> class Statistics {
|
|
|
|
public:
|
|
|
|
/** ctor */
|
|
Statistics() : sum(), sumSquared(), cnt() {;}
|
|
|
|
/** dtor */
|
|
~Statistics() {;}
|
|
|
|
/** add a new value */
|
|
void add(T value) {
|
|
++cnt;
|
|
sum += value;
|
|
sumSquared += (value*value);
|
|
values.insert(value);
|
|
}
|
|
|
|
/** add all values from the given statistics instance */
|
|
void add(const Statistics<T>& other) {
|
|
for (const T val : other.values) {
|
|
this->add(val);
|
|
}
|
|
}
|
|
|
|
/** get the std-dev of all values */
|
|
T getStdDev() const {
|
|
double E1 = sumSquared / (double) cnt;
|
|
double E2 = getAvg();
|
|
return std::sqrt(E1 - (E2*E2));
|
|
}
|
|
|
|
/** get average value */
|
|
T getAvg() const {
|
|
return sum / (double) cnt;
|
|
}
|
|
|
|
/** get the given quantile (e.g. 0.5 for median) */
|
|
T getQuantile(const double q) const {
|
|
if (q < 0) {return *values.begin();}
|
|
if (q >= 1) {return *(--values.end());}
|
|
uint32_t pos = cnt * q;
|
|
uint32_t curPos = 0;
|
|
for (auto val : values) {
|
|
if (curPos == pos) {return val;}
|
|
++curPos;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/** get the median value (= Quantile 0.5) */
|
|
T getMedian() const {
|
|
return getQuantile(0.5f);
|
|
}
|
|
|
|
/** get smallest value */
|
|
T getMin() const {
|
|
if (values.empty()) {return -1;}
|
|
return *(values.begin());
|
|
}
|
|
|
|
/** get largest value */
|
|
T getMax() const {
|
|
if (values.empty()) {return -1;}
|
|
return *(--values.end());
|
|
}
|
|
|
|
/** get the range between min an max */
|
|
T getRange() const {
|
|
return getMax() - getMin();
|
|
}
|
|
|
|
/** get the squared sum */
|
|
T getSquaredSum() const {
|
|
return sumSquared;
|
|
}
|
|
|
|
|
|
/** get the sum of all values */
|
|
T getSum() const {
|
|
return sum;
|
|
}
|
|
|
|
/** get number of stored values */
|
|
uint32_t getCount() const {
|
|
return cnt;
|
|
}
|
|
|
|
/** get the number of values that are below "val" */
|
|
T getNumValuesBelow(uint32_t val) const {
|
|
uint32_t numFound = 0;
|
|
for (auto curVal : values) {
|
|
if (curVal > val) {return numFound;}
|
|
++numFound;
|
|
}
|
|
return numFound;
|
|
}
|
|
|
|
/** get all contained values in ascending order */
|
|
const std::multiset<T>& getAll() const {
|
|
return values;
|
|
}
|
|
|
|
/** get as string */
|
|
std::string asString() const {
|
|
std::stringstream ss;
|
|
appendTo(ss);
|
|
return ss.str();
|
|
}
|
|
|
|
/** send to the given stream */
|
|
void appendTo(std::ostream& out) const {
|
|
out.precision(6);
|
|
out.setf( std::ios::fixed, std:: ios::floatfield );
|
|
out << "cnt(" << getCount() << ")\t";
|
|
out << "min(" << getMin() << ")\t";
|
|
out << "max(" << getMax() << ")\t";
|
|
out << "range(" << getRange() << ")\t";
|
|
out << "med(" << getMedian() << ")\t";
|
|
out << "avg(" << getAvg() << ")\t";
|
|
out << "stdDev(" << getStdDev() << ")\t";
|
|
}
|
|
|
|
/** send to stream */
|
|
inline std::ostream& operator << (std::ostream& out) const {
|
|
appendTo(out); return out;
|
|
}
|
|
|
|
/** reset all statistics */
|
|
void reset() {
|
|
sum = T();
|
|
sumSquared = T();
|
|
cnt = 0;
|
|
values.clear();
|
|
}
|
|
|
|
private:
|
|
|
|
/** sum of all added values */
|
|
T sum;
|
|
|
|
/** squared sum of all added values (for std-dev) */
|
|
T sumSquared;
|
|
|
|
/** the number of added values */
|
|
uint32_t cnt;
|
|
|
|
/** multiset to sort all values */
|
|
std::multiset<T> values;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif // STATISTICS_H
|