#ifndef __statistics_h__
#define __statistics_h__ 1
#include <queue>
#include <cfloat>
namespace utils {
template <class T, class S, class C>
void clearpq(std::priority_queue<T, S, C>& q) {
struct HackedQueue : private std::priority_queue<T, S, C> {
static S& Container(std::priority_queue<T, S, C>& q) {
return q.*&HackedQueue::c;
}
};
HackedQueue::Container(q).clear();
}
class statistics {
size_t N;
double A;
double varL;
double varH;
double m,M;
double Median;
bool computeMedian;
// These heap stores are only used when computeMedian=true.
// Max heap stores the smaller half elements:
std::priority_queue<double> s;
// Min heap stores the greater half elements:
std::priority_queue<double,std::vector<double>,std::greater<double> > g;
public:
statistics(bool computeMedian=false) : computeMedian(computeMedian) {
clear();
}
void clear() {N=0; A=varL=varH=0.0; m=DBL_MAX; M=-m; clearpq(s); clearpq(g);}
double count() {return N;}
double mean() {return A;}
double max() {return M;}
double min() {return m;}
double sum() {return N*A;}
void add(double t) {
++N;
double diff=t-A;
A += diff/N;
double v=diff*(t-A);
if(diff < 0.0)
varL += v;
else
varH += v;
if(t < m) m=t;
if(t > M) M=t;
if(computeMedian) {
if(N == 1)
s.push(Median=t);
else {
if(s.size() > g.size()) { // left side heap has more elements
if(t < Median) {
g.push(s.top());
s.pop();
s.push(t);
} else
g.push(t);
Median=0.5*(s.top()+g.top());
}
else if(s.size() == g.size()) { // both heaps are balanced
if(t < Median) {
s.push(t);
Median=(double) s.top();
} else {
g.push(t);
Median=(double) g.top();
}
}
else { // right side heap has more elements
if(t > Median) {
s.push(g.top());
g.pop();
g.push(t);
} else
s.push(t);
Median=0.5*(s.top()+g.top());
}
}
}
}
double stdev(double var, double f) {
if(N <= f) return DBL_MAX;
return sqrt(var*f/(N-f));
}
double stdev() {
return stdev(varL+varH,1.0);
}
double stdevL() {
return stdev(varL,2.0);
}
double stdevH() {
return stdev(varH,2.0);
}
double stderror() {
return stdev()/sqrt((double) N);
}
double median() {
if(!computeMedian) {
std::cerr << "Constructor requires median=true" << std::endl;
exit(-1);
}
return Median;
}
void output(const char *text, size_t m) {
std::cout << text << ": \n"
<< m << "\t"
<< A << "\t"
<< stdevL() << "\t"
<< stdevH() << std::endl;
}
};
}
#endif