Java 如何将digamma函数重写为非递归函数
我运行了一个java程序,得到了一个Java 如何将digamma函数重写为非递归函数,java,stack-overflow,Java,Stack Overflow,我运行了一个java程序,得到了一个stackoverflow错误,这个错误是由a引起的,代码是 public static double digamma(double x) { if (x >= 0 && x < GAMMA_MINX) { x = GAMMA_MINX; } if (x < DIGAMMA_MINNEGX) { return digamma(DIGAMMA_MINNEGX + GAMMA
stackoverflow错误
,这个错误是由a引起的,代码是
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;
}
由于
stackoverflow错误
是由于递归级别太深,以至于超出了线程的堆栈大小(对吗?),因此我将Xss
参数增加到20M
,但错误仍然存在,因此我认为必须将其重写为非递归,但我没有将递归函数重新编译为非递归函数的经验。未经测试,但它是:
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;
}
}
public静态双数字放大器(双x){
双值=0;
while(true){
如果(x>=0&&x0&&x=C_极限){
双投资=1/(x*x);
返回值+数学日志(x)-0.5/x-库存
*((1.0/12)+inv*(1.0/120-inv/252));
}
值-=1/x;
x=x+1;
}
}
因为代码几乎是尾部递归的,所以技巧是在整个主体上抛出一个循环
捕捉的是结尾处的
-1/x
。但是,由于它是加法的,所以在开始下一次迭代之前,您可以从结果中减去1/x
。您不希望返回
在循环之外,并在正文中包含某种中断
语句吗?这只是风格的问题。否则就没关系了。(除非Java抱怨缺少返回状态。)感谢您的帮助。我看到还有一个递归函数调用在<代码> DigaMa(DigaMaMIN NIGNXX+GAMMAYMIX),所以这不是一个纯非递归版本,那么有没有办法将它改写成纯非递归版本?我忽略了中间调用。我会看看我是否也能摆脱它。实际上,digamma(digamma\u MINNEGX+GAMMA\u MINX)
只是一个常数。你不能预先计算并完全替换它吗?
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;
}
}