1.2.18

上次更新:2019-04-17
发现了题解错误/代码缺陷/排版问题?请点这里:如何:提交反馈

解答

当数据比较大时—— 例如 10^9 加上随机小数组成的数列,这时 double 的小数精度将受限。
求和之后整数部分更大,小数部分将自动四舍五入,出现误差
这时再计算平均值时将会带来较大的误差。
因此采用另一个递推公式:
k 为下标。

$M_k = M_{k-1}+ (x_k – M_{k-1})/k$
$S_k = S_{k-1} + (x_k – M_{k-1})\times(x_k – M_k)$.
方差 $s^2 = S_k/(k – 1)$.

这种情况下并没有直接对所有输入值求和,小数精度不会过多受到整数部分长度的影响。

有关这两个公式的证明可以参考这篇论文,或者去查看我的知乎回答

代码

using System;

namespace _1._2._18
{
    public class Accumulator
    {
        private double m;
        private double s;
        private int N;

        public void AddDataValue(double x)
        {
            N++;
            s = s + 1.0 * (N - 1) / N * (x - m) * (x - m);
            m = m + (x - m) / N;
        }
        public double Mean()
        {
            return m;
        }
        public double Var()
        {
            return s / (N - 1);
        }
        public double Stddev()
        {
            return Math.Sqrt(this.Var());
        }
        public override string ToString()
        {
            return "Mean (" + N + " values): " + string.Format("{0, 7:F5}", Mean());
        }
    }
}
上一题 下一题