-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathOnePassDescriptiveStats.hpp
More file actions
102 lines (87 loc) · 2.46 KB
/
Copy pathOnePassDescriptiveStats.hpp
File metadata and controls
102 lines (87 loc) · 2.46 KB
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
#pragma once
// Copyright (c) 2015 Peter Gaultney — MIT License (see LICENSE)
#include <limits>
// This class is not thread safe.
class OnePassDescriptiveStats
{
public:
void addValue(double value);
double getVariance() const;
double getStddev() const;
OnePassDescriptiveStats aggregateWithSet(const OnePassDescriptiveStats& B) const;
unsigned long long count = 0;
double mean = 0.0;
double min = std::numeric_limits<double>::max();
double max = std::numeric_limits<double>::min();
double M2 = 0.0;
public:
static OnePassDescriptiveStats aggregateSets(
const OnePassDescriptiveStats& A,
const OnePassDescriptiveStats& B);
};
/*
* Implementation sourced from http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
* which is itself (mostly) due to Donald Knuth, according to Wikipedia.
*/
#include <cmath>
inline void OnePassDescriptiveStats::addValue(double value)
{
if (value > this->max) {
this->max = value;
}
if (value < this->min) {
this->min = value;
}
++ this->count;
double delta = value - this->mean;
this->mean = this->mean + delta / this->count;
this->M2 = this->M2 + delta * (value - this->mean);
}
/**
* This is the sample, not population, variance.
*/
inline double OnePassDescriptiveStats::getVariance() const
{
if (this->count < 2) {
return 0.0;
} else {
return this->M2 / (this->count - 1);
}
}
inline double OnePassDescriptiveStats::getStddev() const
{
return sqrt(this->getVariance());
}
inline OnePassDescriptiveStats OnePassDescriptiveStats::aggregateWithSet(
const OnePassDescriptiveStats& B) const
{
return OnePassDescriptiveStats::aggregateSets(*this, B);
}
inline OnePassDescriptiveStats OnePassDescriptiveStats::aggregateSets(
const OnePassDescriptiveStats& A,
const OnePassDescriptiveStats& B)
{
OnePassDescriptiveStats combined;
// this algorithm due to Chan et al., also from Wikipedia page above
double delta = B.mean - A.mean;
combined.count = A.count + B.count;
if (combined.count > 0) {
combined.mean = (A.count * A.mean + B.count * B.mean) / combined.count;
combined.M2 = A.M2 + B.M2 + delta * delta * ((double)(A.count * B.count) / combined.count);
} else { // if we're combining two empty sets, we don't want floating point exceptions.
combined.mean = 0;
combined.M2 = 0;
}
// mins, maxes
if (B.max > A.max) {
combined.max = B.max;
} else {
combined.max = A.max;
}
if (B.min < A.min) {
combined.min = B.min;
} else {
combined.min = A.min;
}
return combined;
}