diff --git a/rtc_base/numerics/samples_stats_counter.cc b/rtc_base/numerics/samples_stats_counter.cc index ac077348e6..1348cbac07 100644 --- a/rtc_base/numerics/samples_stats_counter.cc +++ b/rtc_base/numerics/samples_stats_counter.cc @@ -17,8 +17,12 @@ namespace webrtc { SamplesStatsCounter::SamplesStatsCounter() = default; SamplesStatsCounter::~SamplesStatsCounter() = default; -SamplesStatsCounter::SamplesStatsCounter(SamplesStatsCounter&) = default; +SamplesStatsCounter::SamplesStatsCounter(const SamplesStatsCounter&) = default; +SamplesStatsCounter& SamplesStatsCounter::operator=( + const SamplesStatsCounter&) = default; SamplesStatsCounter::SamplesStatsCounter(SamplesStatsCounter&&) = default; +SamplesStatsCounter& SamplesStatsCounter::operator=(SamplesStatsCounter&&) = + default; void SamplesStatsCounter::AddSample(double value) { samples_.push_back(value); @@ -30,6 +34,7 @@ void SamplesStatsCounter::AddSample(double value) { min_ = value; } sum_ += value; + sum_squared_ += value * value; } double SamplesStatsCounter::GetPercentile(double percentile) { diff --git a/rtc_base/numerics/samples_stats_counter.h b/rtc_base/numerics/samples_stats_counter.h index 88495030c9..a982b2ebf3 100644 --- a/rtc_base/numerics/samples_stats_counter.h +++ b/rtc_base/numerics/samples_stats_counter.h @@ -11,6 +11,7 @@ #ifndef RTC_BASE_NUMERICS_SAMPLES_STATS_COUNTER_H_ #define RTC_BASE_NUMERICS_SAMPLES_STATS_COUNTER_H_ +#include #include #include @@ -22,8 +23,10 @@ class SamplesStatsCounter { public: SamplesStatsCounter(); ~SamplesStatsCounter(); - SamplesStatsCounter(SamplesStatsCounter&); + SamplesStatsCounter(const SamplesStatsCounter&); + SamplesStatsCounter& operator=(const SamplesStatsCounter&); SamplesStatsCounter(SamplesStatsCounter&&); + SamplesStatsCounter& operator=(SamplesStatsCounter&&); // Adds sample to the stats in amortized O(1) time. void AddSample(double value); @@ -49,6 +52,18 @@ class SamplesStatsCounter { RTC_DCHECK(!IsEmpty()); return sum_ / samples_.size(); } + // Returns variance in O(1) time. This function may not be called if there are + // no samples. + double GetVariance() const { + RTC_DCHECK(!IsEmpty()); + return sum_squared_ / samples_.size() - GetAverage() * GetAverage(); + } + // Returns standard deviation in O(1) time. This function may not be called if + // there are no samples. + double GetStandardDeviation() const { + RTC_DCHECK(!IsEmpty()); + return sqrt(GetVariance()); + } // Returns percentile in O(nlogn) on first call and in O(1) after, if no // additions were done. This function may not be called if there are no // samples. @@ -62,6 +77,7 @@ class SamplesStatsCounter { double min_ = std::numeric_limits::max(); double max_ = std::numeric_limits::min(); double sum_ = 0; + double sum_squared_ = 0; bool sorted_ = false; }; diff --git a/rtc_base/numerics/samples_stats_counter_unittest.cc b/rtc_base/numerics/samples_stats_counter_unittest.cc index 713b5f9821..e6d9f6728c 100644 --- a/rtc_base/numerics/samples_stats_counter_unittest.cc +++ b/rtc_base/numerics/samples_stats_counter_unittest.cc @@ -10,6 +10,7 @@ #include "rtc_base/numerics/samples_stats_counter.h" +#include #include #include @@ -17,6 +18,7 @@ namespace webrtc { namespace { + SamplesStatsCounter CreateStatsFilledWithIntsFrom1ToN(int n) { std::vector data; for (int i = 1; i <= n; i++) { @@ -30,35 +32,47 @@ SamplesStatsCounter CreateStatsFilledWithIntsFrom1ToN(int n) { } return stats; } + } // namespace TEST(SamplesStatsCounter, FullSimpleTest) { SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(100); - ASSERT_TRUE(!stats.IsEmpty()); - ASSERT_DOUBLE_EQ(stats.GetMin(), 1.0); - ASSERT_DOUBLE_EQ(stats.GetMax(), 100.0); - ASSERT_DOUBLE_EQ(stats.GetAverage(), 50.5); - ASSERT_DOUBLE_EQ(stats.GetPercentile(0), 1); + EXPECT_TRUE(!stats.IsEmpty()); + EXPECT_DOUBLE_EQ(stats.GetMin(), 1.0); + EXPECT_DOUBLE_EQ(stats.GetMax(), 100.0); + EXPECT_DOUBLE_EQ(stats.GetAverage(), 50.5); for (int i = 1; i <= 100; i++) { double p = i / 100.0; - ASSERT_GE(stats.GetPercentile(p), i); - ASSERT_LT(stats.GetPercentile(p), i + 1); + EXPECT_GE(stats.GetPercentile(p), i); + EXPECT_LT(stats.GetPercentile(p), i + 1); } } +TEST(SamplesStatsCounter, VarianceAndDeviation) { + SamplesStatsCounter stats; + stats.AddSample(2); + stats.AddSample(2); + stats.AddSample(-1); + stats.AddSample(5); + + EXPECT_DOUBLE_EQ(stats.GetAverage(), 2.0); + EXPECT_DOUBLE_EQ(stats.GetVariance(), 4.5); + EXPECT_DOUBLE_EQ(stats.GetStandardDeviation(), sqrt(4.5)); +} + TEST(SamplesStatsCounter, FractionPercentile) { SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(5); - ASSERT_DOUBLE_EQ(stats.GetPercentile(0.5), 3); + EXPECT_DOUBLE_EQ(stats.GetPercentile(0.5), 3); } TEST(SamplesStatsCounter, TestBorderValues) { SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(5); - ASSERT_GE(stats.GetPercentile(0.01), 1); - ASSERT_LT(stats.GetPercentile(0.01), 2); - ASSERT_DOUBLE_EQ(stats.GetPercentile(1.0), 5); + EXPECT_GE(stats.GetPercentile(0.01), 1); + EXPECT_LT(stats.GetPercentile(0.01), 2); + EXPECT_DOUBLE_EQ(stats.GetPercentile(1.0), 5); } } // namespace webrtc