Add running average

This commit is contained in:
Georg Hagen
2025-05-13 17:37:20 +02:00
parent 9215a0a305
commit 28bf76b792
2 changed files with 277 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "Data/Containers/RingBuffer.hpp"
#include <type_traits>
#include <concepts>
namespace OpenVulkano::Math
{
template<typename T>
concept SupportsRunningAverage = requires(T a, T b, int64_t size)
{
{ a += b } -> std::same_as<T&>;
{ a -= b } -> std::same_as<T&>;
{ a * size } -> std::convertible_to<T>;
{ a / size } -> std::convertible_to<T>;
};
template<typename T,
size_t SIZE = RING_BUFFER_DYNAMIC,
bool RECALC = std::is_floating_point_v<T>,
size_t RECALC_OP_COUNT = 100> requires SupportsRunningAverage<T>
class RunningAverage final
{
struct Empty {};
RingBuffer<T, SIZE> m_buffer;
T m_value;
[[no_unique_address]] std::conditional_t<RECALC, size_t, Empty> m_operations;
public:
RunningAverage(size_t size) requires (std::is_default_constructible_v<T> && SIZE == RING_BUFFER_DYNAMIC)
: m_buffer(size), m_value(T() * static_cast<int64_t>(size))
{
assert(size > 0);
m_buffer.Fill(T());
if constexpr (RECALC) m_operations = 0;
}
RunningAverage(size_t size, const T& def) requires (SIZE == RING_BUFFER_DYNAMIC)
: m_buffer(size), m_value(def * static_cast<int64_t>(size))
{
assert(size > 0);
m_buffer.Fill(def);
if constexpr (RECALC) m_operations = 0;
}
RunningAverage() requires (std::is_default_constructible_v<T> && SIZE != RING_BUFFER_DYNAMIC)
: m_value(T() * static_cast<int64_t>(SIZE))
{
static_assert(SIZE > 0);
m_buffer.Fill(T());
if constexpr (RECALC) m_operations = 0;
}
RunningAverage(const T& def) requires (SIZE != RING_BUFFER_DYNAMIC)
: m_value(def * static_cast<int64_t>(SIZE))
{
static_assert(SIZE > 0);
m_buffer.Fill(def);
if constexpr (RECALC) m_operations = 0;
}
void Push(const T& value)
{
m_value -= m_buffer.PushAndOverwrite(value);
m_value += value;
if constexpr (RECALC)
{
if (++m_operations >= RECALC_OP_COUNT)
{
m_operations = 0;
Recalculate();
}
}
}
[[nodiscard]] T Get() const { return m_value / static_cast<int64_t>(m_buffer.Size()); }
void Recalculate()
{
m_value = m_buffer[0];
auto it = m_buffer.cbegin();
it++;
for(auto end = m_buffer.cend(); it != end; it++)
{
m_value += *it;
}
}
};
}