💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
3.9 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_MATH_MOVING_AVERAGE_HPP
  20. #define ANTKEEPER_MATH_MOVING_AVERAGE_HPP
  21. #include <algorithm>
  22. #include <cstdint>
  23. #include <vector>
  24. namespace math {
  25. /**
  26. * Calculates a moving average.
  27. *
  28. * @tparam T Sample value type.
  29. */
  30. template <class T>
  31. class moving_average
  32. {
  33. public:
  34. /// Type of value to average.
  35. using sample_type = T;
  36. /**
  37. * Constructs a moving average
  38. *
  39. * @param capacity Sample capacity.
  40. */
  41. /// @{
  42. explicit moving_average(std::size_t capacity):
  43. m_samples(capacity)
  44. {}
  45. moving_average() noexcept = default;
  46. /// @}
  47. /**
  48. * Adds a sample to the moving average. If the moving average has reached its sample capacity, the oldest sample will be discarded.
  49. *
  50. * @param value Sample value.
  51. *
  52. * @return Current average value.
  53. */
  54. sample_type operator()(sample_type value) noexcept
  55. {
  56. m_sum += value;
  57. if (m_sample_index < m_samples.size())
  58. {
  59. m_samples[m_sample_index] = value;
  60. ++m_sample_index;
  61. m_average = m_sum / static_cast<sample_type>(m_sample_index);
  62. }
  63. else
  64. {
  65. sample_type& sample = m_samples[m_sample_index % m_samples.size()];
  66. m_sum -= sample;
  67. sample = value;
  68. ++m_sample_index;
  69. m_average = m_sum / static_cast<sample_type>(m_samples.size());
  70. }
  71. return m_average;
  72. }
  73. /**
  74. * Resets the moving average.
  75. */
  76. void reset() noexcept
  77. {
  78. m_sample_index = 0;
  79. m_sum = sample_type{0};
  80. m_average = sample_type{0};
  81. }
  82. /**
  83. * Changes the sample capacity of the moving average.
  84. *
  85. * @param capacity Sample capacity.
  86. */
  87. void reserve(std::size_t capacity)
  88. {
  89. m_samples.resize(capacity, sample_type{0});
  90. }
  91. /**
  92. * Changes the current number of samples of the moving average.
  93. *
  94. * @param size Number of samples
  95. */
  96. void resize(std::size_t size)
  97. {
  98. if (size > m_samples.size())
  99. {
  100. m_samples.resize(size);
  101. }
  102. m_sample_index = size;
  103. }
  104. /// Returns a pointer to the sample data.
  105. [[nodiscard]] inline constexpr sample_type* data() const noexcept
  106. {
  107. return m_samples.data();
  108. }
  109. /// Returns the current moving average value.
  110. [[nodiscard]] inline sample_type average() const noexcept
  111. {
  112. return m_average;
  113. }
  114. ///Returns the sum of all current samples.
  115. [[nodiscard]] inline sample_type sum() const noexcept
  116. {
  117. return m_sum;
  118. }
  119. /// Returns the current number of samples.
  120. [[nodiscard]] inline std::size_t size() const noexcept
  121. {
  122. return std::min<std::size_t>(m_sample_index, m_samples.size());
  123. }
  124. /// Returns the maximum number of samples.
  125. [[nodiscard]] inline constexpr std::size_t capacity() const noexcept
  126. {
  127. return m_samples.size();
  128. }
  129. /// Return `true` if there are currently no samples in the average, `false` otherwise.
  130. [[nodiscard]] inline constexpr bool empty() const noexcept
  131. {
  132. return !m_sample_index;
  133. }
  134. /// Return `true` if the number of samples in the average has reached its capacity, `false` otherwise.
  135. [[nodiscard]] inline constexpr bool full() const noexcept
  136. {
  137. return m_sample_index >= m_samples.size();
  138. }
  139. private:
  140. std::vector<sample_type> m_samples;
  141. std::size_t m_sample_index{0};
  142. sample_type m_sum{0};
  143. sample_type m_average{0};
  144. };
  145. } // namespace math
  146. #endif // ANTKEEPER_MATH_MOVING_AVERAGE_HPP