Suppose I have a long, possibly infinite, sequence $x := [x_1, x_2, ...]$, and I want to use it to compute another sequence $y:=[y_1, y_2, ...]$ where each element is the sum of the last K elements of the input sequence. i.e.
$y_i = \sum_{j=max(1, i-K)}^i x_j$
The naive, inefficient way to do (in Python) this would be:
def sum_of_last_k(x: Sequence[float], k: int):
buffer = [0. ] * k # Initialize a buffer of k zeros
for i, xi in enumerate(x):
buffer[i % k] = xi # Where % is modulo
yield sum(buffer)
... Which would have $\mathcal O(K)$ efficiency per iteration. However, I want to do it online and efficiently. We could do this in $\mathcal O(1)$ by keeping a running sum:
def sum_of_last_k(x: Sequence[float], k: int):
buffer = [0. ] * (k-1) # Initialize a buffer of k-1 zeros
running_sum = 0
for i, xi in enumerate(x):
ix_wrapped = i % (k-1)
old_value = buffer[ix_wrapped]
buffer[ix_wrapped] = xi
running_sum = running_sum + xi - old_value
yield running_sum
This has $\mathcal O(1)$ efficiency, but there is still a problem: Due to floating-point precision errors, there can be a rounding error in running_sum which accumulates over time.
Now I know I could just resolve this by recomputing running_sum from scratch every M iterations, where M is some large number, and have the average runtime be $\mathcal O((M-1+K)/M)$ which may be very close to 1... But I want the worst case runtime to be $\mathcal O(1)$, not $\mathcal O(K)$.
So, is there some way to compute this in $\mathcal O(1)$ time per iteration while still being numerically stable?