如何将digamma函数重写为非递归函数

时间:2013-04-28 02:07:17

标签: java stack-overflow

我运行了一个java程序并获得stackoverflow error,这个错误是由digamma function引起的,代码是

public static double digamma(double x) {
    if (x >= 0 && x < GAMMA_MINX) {
        x = GAMMA_MINX;
    }
    if (x < DIGAMMA_MINNEGX) {
        return digamma(DIGAMMA_MINNEGX + GAMMA_MINX);
    }
    if (x > 0 && x <= S_LIMIT) {
        return -GAMMA - 1 / x;
    }

    if (x >= C_LIMIT) {
        double inv = 1 / (x * x);
        return Math.log(x) - 0.5 / x - inv
                * ((1.0 / 12) + inv * (1.0 / 120 - inv / 252));
    }
    return digamma(x + 1) - 1 / x;
}

常量定义如下(省略private static final以供空间考虑)

double GAMMA = 0.577215664901532860606512090082;
double GAMMA_MINX = 1.e-12;
double DIGAMMA_MINNEGX = -1250;
double C_LIMIT = 49;
double S_LIMIT = 1e-5;

由于stackoverflow error是由递归级别太深导致超出线程的堆栈大小(对吗?)所以我将Xss参数增加到{{1}但是错误仍然存​​在,所以我认为我必须将其重写为非递归,但我没有将递归函数重写为非递归的经验。

1 个答案:

答案 0 :(得分:1)

未经测试,但现在是:

public static double digamma(double x) {

    double value = 0;

    while (true){

        if (x >= 0 && x < GAMMA_MINX) {
            x = GAMMA_MINX;
        }
        if (x < DIGAMMA_MINNEGX) {
            x = DIGAMMA_MINNEGX + GAMMA_MINX;
            continue;
        }
        if (x > 0 && x <= S_LIMIT) {
            return value + -GAMMA - 1 / x;
        }

        if (x >= C_LIMIT) {
            double inv = 1 / (x * x);
            return value + Math.log(x) - 0.5 / x - inv
                    * ((1.0 / 12) + inv * (1.0 / 120 - inv / 252));
        }

        value -= 1 / x;
        x = x + 1;
    }

}

由于代码几乎是尾递归的,所以诀窍是在整个身体上抛出一个循环。

捕获量是你最后的- 1 / x。但由于它是附加的,你可以在开始下一次迭代之前从结果中减去1 / x