对于计算所有值的总和超过双精度值限制的平均值,什么是一个好的解决方案?

2022-08-31 20:20:03

我需要计算一组非常大的双精度值(10^9 个值)的平均值。值的总和超过了双精度值的上限,那么有没有人知道计算平均值的巧妙的小技巧,而不需要计算总和?

我使用的是 Java 1.5。


答案 1

您可以迭代计算平均值。这个算法简单,快速,你必须只处理一次每个值,变量永远不会大于集合中的最大值,所以你不会得到溢出。

double mean(double[] ary) {
  double avg = 0;
  int t = 1;
  for (double x : ary) {
    avg += (x - avg) / t;
    ++t;
  }
  return avg;
}

循环内部始终是到目前为止处理的所有值的平均值。换句话说,如果所有值都是有限的,则不应溢出。avg


答案 2

我想问你的第一个问题是:

  • 您事先知道值的数量吗?

如果没有,那么你别无选择,只能求和,计数,除以做平均值。如果精度不够高来处理这个问题,那么运气不好,你不能用,你需要找到一个可以处理它的数据类型。DoubleDouble

另一方面,如果您事先知道值的数量,则可以查看您真正在做什么并更改其操作方式,但保留整体结果。

存储在某个集合 A 中的 N 个值的平均值是:

A[0]   A[1]   A[2]   A[3]          A[N-1]   A[N]
---- + ---- + ---- + ---- + .... + ------ + ----
 N      N      N      N               N       N

要计算此结果的子集,您可以将计算拆分为大小相等的集合,因此对于 3 值集可以执行此操作(假设值的数量可被 3 整除,否则需要不同的除数)

/ A[0]   A[1]   A[2] \   / A[3]   A[4]   A[5] \   //      A[N-1]   A[N] \
| ---- + ---- + ---- |   | ---- + ---- + ---- |   \\    + ------ + ---- |
\  3      3      3   /   \  3      3      3   /   //        3       3   /
 --------------------- +  --------------------  + \\      --------------
          N                        N                        N
         ---                      ---                      ---
          3                        3                        3

请注意,您需要大小相等的集合,否则最后一个集合中的数字(与之前的所有集合相比没有足够的值)将对最终结果产生更大的影响。

按顺序考虑数字 1-7,如果选择 3 的集合大小,则得到以下结果:

/ 1   2   3 \   / 4   5   6 \   / 7 \ 
| - + - + - | + | - + - + - | + | - |
\ 3   3   3 /   \ 3   3   3 /   \ 3 /
 -----------     -----------     ---
      y               y           y

它给出:

     2   5   7/3
     - + - + ---
     y   y    y

如果 y 对于所有集合都是 3,则得到:

     2   5   7/3
     - + - + ---
     3   3    3

它给出:

2*3   5*3    7
--- + --- + ---
 9     9     9

即:

6   15   7
- + -- + -
9    9   9

总计:

28
-- ~ 3,1111111111111111111111.........1111111.........
 9

1-7的平均值为4。显然,这行不通。请注意,如果您使用数字1,2,3,4,5,6,7,0,0(请注意最后两个零)进行上述练习,那么您将获得上述结果。

换句话说,如果无法将值的数量拆分为大小相等的集合,则最后一个集合将被计数,就好像它具有与它之前的所有集合相同的值数一样,但对于所有缺失值,它将用零填充。

因此,您需要同等大小的套装。如果您的原始输入集由素数值组成,则运气不好。

不过,我在这里担心的是精度的损失。我不完全确定在这种情况下会给你足够的精度,如果它最初不能容纳整个值的总和。Double