#include <iostream>
#include <iomanip>
template <typename T, int WindowSize>
class MovingAverage {
private:
T buffer[WindowSize];
int count; // Total valid samples added so far (capped at WindowSize)
int index; // Where to write the *next* sample
public:
MovingAverage() : count(0), index(0) {}
T addSample(T sample) {
// Overwrite oldest sample
buffer[index] = sample;
// Move index circularly
index = (index + 1) % WindowSize;
// Track how many items we have valid
if (count < WindowSize) {
count++;
}
// Calculate Average
T sum = 0;
for (int i = 0; i < count; ++i) {
sum += buffer[i];
}
return sum / count;
}
};
int main() {
MovingAverage<float, 4> filter;
int N;
if (!(std::cin >> N)) return 0;
for (int i = 0; i < N; ++i) {
float sample;
std::cin >> sample;
float avg = filter.addSample(sample);
std::cout << "Avg: " << std::fixed << std::setprecision(2) << avg << std::endl;
}
return 0;
}Explanation & Logic Summary:
WindowSize a template parameter, the compiler creates a fixed-size array buffer[4], avoiding the runtime overhead of pointers and heap allocation (malloc).index wraps around using modulo (% WindowSize). This overwrites the oldest data naturally.if (count < WindowSize) count++; handles the startup transient where the buffer isn't full yet (e.g., dividing by 1, then 2, then 3).Firmware Relevance & Real-World Context:
WindowSize is known at compile time, the compiler can unroll the summation loop or use SIMD instructions on advanced DSP chips.float and size 4.
Input
5 10.0 20.0 30.0 40.0 50.0
Expected Output
Avg: 10.00 Avg: 15.00 Avg: 20.00 Avg: 25.00 Avg: 35.00