Skip to content

Instantly share code, notes, and snippets.

@insaneyilin
Created November 29, 2021 11:44
Show Gist options
  • Save insaneyilin/915727c485449cdcc555c6b5209b7e24 to your computer and use it in GitHub Desktop.
Save insaneyilin/915727c485449cdcc555c6b5209b7e24 to your computer and use it in GitHub Desktop.
Welford's online algorithm for calculating variance
#pragma once
#include <cmath>
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
template <typename T>
class WelfordMeanStddevCalculator {
public:
WelfordMeanStddevCalculator() = default;
virtual ~WelfordMeanStddevCalculator() = default;
void Add(T x) {
++count_;
const T delta = x - mean_;
mean_ += delta / T(count_);
const T delta2 = x - mean_;
sum_of_squares_ += delta * delta2;
if (count_ > 1) {
stddev_ = std::sqrt(sum_of_squares_ / T(count_ - 1));
}
}
T mean() const { return mean_; }
T stddev() const { return stddev_; }
int count() const { return count_; }
private:
T mean_ = T(0);
T sum_of_squares_ = T(0);
T stddev_ = T(0);
int count_ = 0;
// Shallow copy is allowed.
};
#include "welford.h"
#include <vector>
#include "gtest/gtest.h"
TEST(WelfordMeanStddevCalculatorTest, Basic) {
const std::vector<double> values = {
0.0, 3.0, 2.0, 11.0, 100.1, 54.3, -20.0,
};
const MeanAndStddev mean_stddev = CalMeanAndStddev(values);
WelfordMeanStddevCalculator<double> calculator;
for (double value : values) {
calculator.Add(value);
}
EXPECT_NEAR(calculator.mean(), mean_stddev.mean, 1e-5);
EXPECT_NEAR(calculator.stddev(), mean_stddev.stddev, 1e-5);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment