8

I occasionally get a stackoverflow exception in this method.

double norm_cdf(const double x) {
    double k = 1.0/(1.0 + 0.2316419*x);
    double k_sum = k*(0.319381530 + k*(-0.356563782 + k*(1.781477937 + k*(-1.821255978 + 1.330274429*k))));

    if (x >= 0.0) {
        return (1.0 - (1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x) * k_sum);
    } else {
        return 1.0 - norm_cdf(-x);
    }
}

Any suggestions on why i might be getting it ? Any steps I can take to rectify the error ?

4

3 回答 3

24

你的问题是什么时候x不是数字。NAN >= 0.0是假的,-NAN >= 0.0也是假的。

正如其他人所建议的那样,您可以特别检查 NAN,但我建议简化一些事情:

static double norm_cdf_positive(const double x) {
    double k = 1.0/(1.0 + 0.2316419*x);
    double k_sum = k*(0.319381530 + k*(-0.356563782 + k*(1.781477937 + k*(-1.821255978 + 1.330274429*k))));

    return (1.0 - (1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x) * k_sum);
}

double norm_cdf(const double x) {
    if (x >= 0.0) {
        return norm_cdf_positive(x);
    } else {
        return 1.0 - norm_cdf_positive(-x);
    }
}

这样做的好处是编译器可以对其行为做出更明智的假设。请注意,我已将“内部”函数标记为静态(这会将其范围限制为当前编译单元)。您还可以使用未命名的命名空间。(编辑:实际上蒂莫西·希尔兹(Timothy Shields)有一种更简单的去除递归的方法,它将所有东西都放在一个函数中)

于 2013-08-09T20:20:30.317 回答
15

这种方法很可能只是压垮骆驼的最后一根稻草。这个函数最多只会调用一次自己,所以这不是问题。(编辑:或者是其他人指出的 NAN 问题,这导致无限递归。)

无论如何,您都可以轻松地使函数不递归,这可能是一个更简单的选择。

double norm_cdf(double x) {
    bool negative = x < 0;
    x = abs(x);
    double k = 1.0/(1.0 + 0.2316419*x);
    double k_sum = k*(0.319381530 + k*(-0.356563782 + k*(1.781477937 + k*(-1.821255978 + 1.330274429*k))));

    double result = (1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x) * k_sum;
    if (!negative)
        result = 1.0 - result;
    return result;
}
于 2013-08-09T20:21:43.453 回答
8

xNaN时,递归将永远不会终止。添加检查:std::isnan在 C++11 中,或者 lazyx != x或者 document-and-blame-user。如果您选择处理NaN,传播它可能是一个明智的选择。

于 2013-08-09T20:18:52.683 回答