rolling_accumulator.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * Copyright 2011 The WebRTC Project Authors. All rights reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #ifndef RTC_BASE_ROLLING_ACCUMULATOR_H_
  11. #define RTC_BASE_ROLLING_ACCUMULATOR_H_
  12. #include <stddef.h>
  13. #include <algorithm>
  14. #include <vector>
  15. #include "rtc_base/checks.h"
  16. #include "rtc_base/constructor_magic.h"
  17. #include "rtc_base/numerics/running_statistics.h"
  18. namespace rtc {
  19. // RollingAccumulator stores and reports statistics
  20. // over N most recent samples.
  21. //
  22. // T is assumed to be an int, long, double or float.
  23. template <typename T>
  24. class RollingAccumulator {
  25. public:
  26. explicit RollingAccumulator(size_t max_count) : samples_(max_count) {
  27. RTC_DCHECK(max_count > 0);
  28. Reset();
  29. }
  30. ~RollingAccumulator() {}
  31. size_t max_count() const { return samples_.size(); }
  32. size_t count() const { return static_cast<size_t>(stats_.Size()); }
  33. void Reset() {
  34. stats_ = webrtc::webrtc_impl::RunningStatistics<T>();
  35. next_index_ = 0U;
  36. max_ = T();
  37. max_stale_ = false;
  38. min_ = T();
  39. min_stale_ = false;
  40. }
  41. void AddSample(T sample) {
  42. if (count() == max_count()) {
  43. // Remove oldest sample.
  44. T sample_to_remove = samples_[next_index_];
  45. stats_.RemoveSample(sample_to_remove);
  46. if (sample_to_remove >= max_) {
  47. max_stale_ = true;
  48. }
  49. if (sample_to_remove <= min_) {
  50. min_stale_ = true;
  51. }
  52. }
  53. // Add new sample.
  54. samples_[next_index_] = sample;
  55. if (count() == 0 || sample >= max_) {
  56. max_ = sample;
  57. max_stale_ = false;
  58. }
  59. if (count() == 0 || sample <= min_) {
  60. min_ = sample;
  61. min_stale_ = false;
  62. }
  63. stats_.AddSample(sample);
  64. // Update next_index_.
  65. next_index_ = (next_index_ + 1) % max_count();
  66. }
  67. double ComputeMean() const { return stats_.GetMean().value_or(0); }
  68. T ComputeMax() const {
  69. if (max_stale_) {
  70. RTC_DCHECK(count() > 0)
  71. << "It shouldn't be possible for max_stale_ && count() == 0";
  72. max_ = samples_[next_index_];
  73. for (size_t i = 1u; i < count(); i++) {
  74. max_ = std::max(max_, samples_[(next_index_ + i) % max_count()]);
  75. }
  76. max_stale_ = false;
  77. }
  78. return max_;
  79. }
  80. T ComputeMin() const {
  81. if (min_stale_) {
  82. RTC_DCHECK(count() > 0)
  83. << "It shouldn't be possible for min_stale_ && count() == 0";
  84. min_ = samples_[next_index_];
  85. for (size_t i = 1u; i < count(); i++) {
  86. min_ = std::min(min_, samples_[(next_index_ + i) % max_count()]);
  87. }
  88. min_stale_ = false;
  89. }
  90. return min_;
  91. }
  92. // O(n) time complexity.
  93. // Weights nth sample with weight (learning_rate)^n. Learning_rate should be
  94. // between (0.0, 1.0], otherwise the non-weighted mean is returned.
  95. double ComputeWeightedMean(double learning_rate) const {
  96. if (count() < 1 || learning_rate <= 0.0 || learning_rate >= 1.0) {
  97. return ComputeMean();
  98. }
  99. double weighted_mean = 0.0;
  100. double current_weight = 1.0;
  101. double weight_sum = 0.0;
  102. const size_t max_size = max_count();
  103. for (size_t i = 0; i < count(); ++i) {
  104. current_weight *= learning_rate;
  105. weight_sum += current_weight;
  106. // Add max_size to prevent underflow.
  107. size_t index = (next_index_ + max_size - i - 1) % max_size;
  108. weighted_mean += current_weight * samples_[index];
  109. }
  110. return weighted_mean / weight_sum;
  111. }
  112. // Compute estimated variance. Estimation is more accurate
  113. // as the number of samples grows.
  114. double ComputeVariance() const { return stats_.GetVariance().value_or(0); }
  115. private:
  116. webrtc::webrtc_impl::RunningStatistics<T> stats_;
  117. size_t next_index_;
  118. mutable T max_;
  119. mutable bool max_stale_;
  120. mutable T min_;
  121. mutable bool min_stale_;
  122. std::vector<T> samples_;
  123. RTC_DISALLOW_COPY_AND_ASSIGN(RollingAccumulator);
  124. };
  125. } // namespace rtc
  126. #endif // RTC_BASE_ROLLING_ACCUMULATOR_H_