如果我们天真地计算平均值:
std::vector<double> values;
double sum = std::accumulate(begin(values), end(values), 0.0);
double mean = sum / values.size();
且values.size()
很大,我们可能会得到不准确的结果,因为浮点数在较高范围内分辨率较低。或者更糟糕的是,如果我理解正确,我们可以获得无限的结果。
当我们有偶数数量的值时,我们可以计算上半部分的平均值,然后计算第二部分的平均值,并找到这两种均值的平均值。
这似乎不是一个新问题,但我无法找到资源。我认为权衡 更复杂的技术
我想知道是否有人将它们总结到某个地方,如果它们在某些库中可用,那就更好了。
答案 0 :(得分:8)
您可以使用here所述的在线算法。
基本上(在pythonish伪代码中):
n = 0
mean = 0
for value in data:
n += 1
mean += (value - mean)/n
该算法在数值上比天真的实现更稳定。
答案 1 :(得分:8)
这里可能会发生很多愚蠢的事情。一个问题是溢出的东西。另一个例子如下:(1e100 + 1) - 1e100) == 0
。另一个是刚刚累积的结果。
Kahan summation可以很好地处理累积的舍入。使用Kahan求和求和,然后除以数据的数量。
为了处理数据不佳的数据,您可以按指数(比如50个不同的桶,每个桶覆盖大约20个不同的指数)和Kahan-sum以递减的桶顺序存储数据。
当然,这都是大规模的矫枉过正,而且速度相当慢。在实践中,使用向量指令和类似的东西可以精确地帮助提高速度和。
答案 2 :(得分:4)
如果您愿意在此过程中使用values
,那么一个简单而强大的方案就是首先对其进行排序:
struct fabs_less
{
bool
operator()(const double x0, const double x1) const
{
return fabs(x0)<fabs(x1);
}
};
std::sort(values.begin(), values.end(), fabs_less());
const double sum = std::accumulate(values.begin(), values.end(), 0.0);
const double mean = sum / double(values.size());
这会将计算复杂度增加到N log N,但会导致最小的舍入误差。
编辑:tmyklebu对退化案例提出了非常好的观点(诅咒我错过了它)。而是按照增加的顺序单独累积负面和正面术语:
std::sort(values.begin(), values.end());
std::vector<double>::const_iterator mid = std::upper_bound(values.begin(), values.end(), 0.0);
std::reverse_iterator<std::vector<double>::const_iterator> rmid(mid);
const double neg = std::accumulate(rmid, values.rend(), 0.0);
const double pos = std::accumulate(mid, values.end(), 0.0);
const double mean = (neg+pos) / double(values.size());
这引入了neg+pos
中取消错误的可能性,但相对于values
元素的绝对值之和仍然会有一个小错误,我认为这是最好的希望没有一些严重复杂的逻辑...
答案 3 :(得分:2)
通常,分而治之的技术(两部分的递归分割)是健壮的。
请参阅我对Precise sum of floating point numbers的回答,其中我以递归形式演示了它。
请注意,在C / C ++中没有递归尾调用消除,因此这种实现不一定有效(它会导致深层堆栈)。
答案 4 :(得分:1)
请原谅,由于长度的原因,不要将此作为评论。 double值通常具有超过50位的精度。你谈论的是万亿分之一以上的一部分。
在整个范围内,浮点数的分辨率在小数基础上保持不变。
但是,如果您将1234E40添加到1234E-040,那么您将获得1234E40。通过平均关闭来添加不同数量级的值。但是,它关闭的数量通常很小(万亿分之一),很少引人注目。
几乎在所有情况下,您只需添加并除以计数即可进行平均,并获得非常精确的答案。
您甚至可以在系统上进行长时间的双击。
如果你有一些数据集不是这种情况,也许你可以描述这个数据集及其出现的问题。由此,我们可以为您的特定问题找到解决方案。