以恒定时间更新连续数字序列的平均值

时间:2014-04-10 21:36:26

标签: performance math iteration time-complexity average

如何在平均值中添加和减去数字而不必遍历整个列表?

这在许多情况下非常有用。例如,连续计算流中最后X个值的平均值,将两个平均值相加,并根据新用户投票更新评级。

2 个答案:

答案 0 :(得分:18)

确实可以在恒定时间内平均操作单个值O(1)。

以下函数会为平均值添加数字。 average是当前的平均值,size是平均值中的当前值,value是要添加到平均值的数字:

double addToAverage(double average, int size, double value)
{
    return (size * average + value) / (size + 1);
}

同样,以下函数从平均值中删除一个数字:

double subtractFromAverage(double average, int size, double value)
{
    return (size * average - value) / (size - 1);
}

您还可以组合这些功能以轻松替换数字。如果要计算数组/流中最后X个数的平均值,这非常方便。

double replaceInAverage(double average, int size, double oldValue, double newValue)
{
    return (size * average - oldvalue + newValue) / size;
}

也可以在恒定时间内计算两个平均值的总平均值:

double addAveragesTogether(double averageA, int sizeA, double averageB, int sizeB)
{
    return (sizeA * averageA + sizeB * averageB) / (sizeA + sizeB);
}

答案 1 :(得分:3)

已经提到的典型方法是:

( n * a + v ) / n + 1;

其中n是我们的新计数,a是我们的旧平均值,v是我们的新值。

但是,n * a部分会最终溢出 ,尤其是在n本身较大的情况下。为了避免这种用法:

a

随着a + ( v - a ) / n 的增加,我们的确损失了一些精度-自然地,我们正在依次减小n的数量。批处理值可以缓解此问题,但对于大多数任务来说可能会显得过大。