如何在平均值中添加和减去数字而不必遍历整个列表?
这在许多情况下非常有用。例如,连续计算流中最后X个值的平均值,将两个平均值相加,并根据新用户投票更新评级。
答案 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
的数量。批处理值可以缓解此问题,但对于大多数任务来说可能会显得过大。