此方法中堆栈溢出的原因(浮点数学)

时间:2013-08-09 20:14:43

标签: c++ stack-overflow

我偶尔会在此方法中获得stackoverflow异常。

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);
    }
}

有关为什么我可能会得到它的任何建议?我可以采取哪些措施来纠正错误?

3 个答案:

答案 0 :(得分: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有一种更简单的方法可以删除递归,这可以将所有内容保存在一个函数中)

答案 1 :(得分: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;
}

答案 2 :(得分:8)

xNaN时,递归永远不会终止。添加一个检查:C ++ 11中的std::isnan,或者懒惰的x != x或文档和责任用户。如果您选择处理NaN,那么传播它可能是一个明智的选择。