3

在寻找 Excel NORMDIST(累积)函数的 C++ 实现时,我在网站上找到了这个

static double normdist(double x, double mean, double standard_dev)
{
    double res;
    double x=(x - mean) / standard_dev;
    if (x == 0)
    {
        res=0.5;
    }
    else
    {
        double oor2pi = 1/(sqrt(double(2) * 3.14159265358979323846));
        double t = 1 / (double(1) + 0.2316419 * fabs(x));
        t *= oor2pi * exp(-0.5 * x * x) 
             * (0.31938153   + t 
             * (-0.356563782 + t
             * (1.781477937  + t 
             * (-1.821255978 + t * 1.330274429))));
        if (x >= 0)
        {
            res = double(1) - t;
        }
        else
        {
            res = t;
        }
    }
    return res;
}

我有限的数学知识让我想到了泰勒级数,但我无法确定这些数字的来源:

0.2316419, 0.31938153, -0.356563782, 1.781477937, -1.821255978, 1.330274429

任何人都可以建议它们来自哪里,以及它们是如何得到的?

4

1 回答 1

10

查看数字食谱,第 6.2.2 章。近似值是标准的。回顾

NormCdf(x) = 0.5 * (1 + erf(x / sqrt(2)))
erf(x) = 2 / (sqrt(pi)) integral(e^(-t^2) dt, t = 0..x)

并将erf写为

1 - erf x ~= t * exp(-x^2 + P(t))

对于正 x,其中

t = 2 / (2 + x)

并且由于 t 在 0 和 1 之间,您可以通过Chebyshev 近似一劳永逸地找到 P(数值食谱,第 5.8 节)。您不使用泰勒展开:您希望近似在整个实线上都很好,这是泰勒展开无法保证的。Chebyshev 近似是L^2 范数中的最佳多项式近似,它很好地替代了很难找到的极小极大多项式(= sup 范数中的最佳多项式近似)。

这里的版本略有不同。相反,一个人写道

1 - erf x = t * exp(-x^2) * P(t)

但过程类似,normCdf 是直接计算的,而不是 erf。

特别是非常相似,您使用的“实现”与文本中处理的“实现”有所不同,因为它是形式b*exp(-a*z^2)*y(t),但也是 Chevishev 近似值。到 erfc(x) 函数,正如您在 Schonfelder(1978) 的这篇论文中看到的那样 [ http://www.ams.org/journals/mcom/1978-32-144/S0025-5718-1978-0494846-8/ S0025-5718-1978-0494846-8.pdf ]

同样在 Numerical Recipes 第 3 版中,在第 6.2.2 章的最后,它们提供了一个非常精确的类型的 C 实现t*exp(-z^2 + c0 + c1*t+ c2t^2 + c3*t^3 + ... + c9t^9)

于 2011-02-08T14:30:52.060 回答