Error: C stack usage 7970184 is too close to the limit

Error: C stack usage 7970184 is too close to the limit

我想计算 RSI 函数,其给出如下:

RSI = 100 * RS / ( 1 + RS ), where        RS = n_up / n_down

                             and   n_up( t ) = ( 1 - b ) *   n_up( t - 1 )
                                             +       b   *      U( t     ),

                             and n_down( t ) = ( 1 - b ) * n_down( t - 1 )
                                             +       b   *      D( t     ).  

                             where    U( t ) = 1  for P( t ) >  P( t - 1 ) and
                                               0  otherwise;

                             and      D( t ) = 1  for P( t ) <  P( t - 1 ) and
                                               0  otherwise.

所以这是我的代码:

p <- data[,6]


rsi <- function(P,t,n)
{
  U <- function(P,t)
  {
    if (diff(P)[t] > 0) 
    {
      return(1)
    } else {
      return(0)
    }
  }

  D <- function(P,t)
  {
    if (diff(P)[t] < 0) 
    {
      return(1)
    } else {
      return(0)
    }
  }

  recursive.n_up <- function(P,t,b)
  {
    return((1-b)*recursive.n_up(P,t-1,b) + b*U(P,t))
  }

  recursive.n_down <- function(P,t,b)
  {
    return((1-b)*recursive.n_down(P,t-1,b) + b*D(P,t))  
  }

  b <- 2/(n+1)
  rs <- function(P,t,b)
  {
    return(recursive.n_up(P,t,b)/recursive.n_down(P,t,b))
  }
  return(100*rs(P,t,b)/(1+rs(P,t,b)))
}

n <- 14
RSI <- rep(0,length(p)-1)
for (i in 1:length(RSI))
{
  RSI[i] <- rsi(p,i,n)
}

print(RSI)

我收到一条错误消息:

C stack usage 7970184 is too close to
the limit

所以我想知道我的算法设计是否非常糟糕,或者这是使用递归函数时的预期结果?谢谢你帮我解决这个问题。

是的,您的递归公式很糟糕,
技术和性能方面:

虽然已知递归可能有助于以一种聪明的方式制定一些问题,但核心逻辑是,它必须有一些 "bottom" 行,其中递归停止任何更深入的 -是一个容易决定的点——从这里开始,到目前为止的嵌套递归开始 return 返回并且(正在返回第一个调用者的路上)递归-returning 过程 assemble 这是正确答案,作为从已知 return 值的已知、容易决定的点的最深层次出现的副作用。

简而言之,您的算法中缺少这一点。

即使在 TimeSeries 数据的第一个历史柱上,您的代码也会尝试越来越深入(及时回溯)。

如果您正确处理这种情况,代码将停止其无限深入的成功习惯,并将开始 assemble 结果。

接下来是性能:

递归适用于一站式微积分。

递归对于重复演算来说是个坏主意,如果已经计算过的 "steps" 再次被重新计算,如果一个糟糕的价值重用政策强制一次又一次地重新潜入并再次返回并且再次回到完全相同的 "terminal point",只是由于原始的(性能未优化)递归公式。

让我们用阶乘来展示它。

出于说明目的,使用其简单的、有史以来最简单的递归形式,而所有原则都与任何更复杂的基于递归的处理相关——这个只适用于一个 SLOC:
factorial( N ) = ( N == 1 ) ? 1 : N * factorial( N - 1 )

如果只是为了计算一次factorial( 15 ),一个词不能反对整个链:

fact15 = ( 15 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 )

缺少任何一个步骤都会导致无法正确计算阶乘。

如果下一个任务是计算下一个 - factorial( 16 )

,则可以从不同的角度看待问题

无视性能的实现会走同一条路来回走:

fact16 = ( 16 * 15 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 )

而一个聪明的、以性能为导向的实现永远不会重复马戏团的尾部,而只会增加头部:

fact16 = ( 16 * fact15 )

从不重复已经计算过的部分。

你看到影响了吗?

想象一下随着递归深度增长到惊人的数百、数千、数万、数十万、数百万递归步骤时这种明显差异的规模......下次再次重复每一个步骤一次又一次。没有。从来没有。

这是所有高性能、低延迟 TimeSeries 数据处理的核心逻辑,RSI 是您自己遇到的明显情况。

完全同意user3666197之前的回答;您的递归函数中没有停止条件。它会一直持续下去....

此外,你在函数中做了一些非常低效的事情。你计算

return( 100 *       rs( P, t, b )
            / ( 1 + rs( P, t, b )
              )
        )  

因此 rs(...) 使用完全相同的参数计算了两次。为什么不是这个:

Z <- rs( P, t, b )
return( 100 * Z / ( 1 + Z )

你必须整合一个合适的停止条件。

对我来说,我使用以下方法清除了 R 并使其正常工作:

#Clear plots
if(!is.null(dev.list())) dev.off()

# Clear console
cat("4") 

# Clean workspace
rm(list=ls())