【问题标题】:Error: C stack usage 7970184 is too close to the limit错误:C 堆栈使用 7970184 太接近限制
【发布时间】:2018-05-09 02:36:29
【问题描述】:

我想计算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 堆栈使用 7970184 太接近了
极限

所以我想知道我的算法设计很糟糕,还是在使用递归函数时会出现这种情况?谢谢你帮我解决这个问题。

【问题讨论】:

    标签: r recursion quantitative-finance


    【解决方案1】:

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

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

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

    所以rs(...) 使用完全相同的参数计算了两次。为什么不这样:

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

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

    【讨论】:

    • 核心效率低下不是在一个时间步内执行“两次”递归,而是 “重复所有” 过去的递归步骤 每个 下一个步。这是幼稚的 TimeSeries 数据处理中的核心性能杀手......
    【解决方案2】:

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

    #Clear plots
    if(!is.null(dev.list())) dev.off()
    
    # Clear console
    cat("\014") 
    
    # Clean workspace
    rm(list=ls())
    

    【讨论】:

      【解决方案3】:

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

      虽然已知递归可能有助于以一种智能的方式制定一些问题,但核心逻辑是,它必须有一些“底线”,即递归停止更深层次——这是一个容易决定的点——到目前为止的嵌套递归从该点开始返回,并且(正在返回第一个调用者的路上)递归返回过程组装正确答案作为从最深处出现的副作用从已知返回值的那个已知的、容易确定的点出发的水平。

      简单地说,这是您的算法中缺少的。

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

      如果你处理得当,代码将停止其无限深潜的连续习惯,并开始组装结果。

      接下来是性能:

      递归适用于一站式演算。

      递归对于重复演算来说是个坏主意,如果已经计算过的“步骤”再次被重新计算,如果一个糟糕的价值重用政策强制一次又一次地重新潜水,一次又一次地回到非常相同的“终点”,只是由于原始(性能未优化)递归公式。

      让我们在阶乘上展示它。

      出于说明目的,使用其最简单、最简单的递归形式,而所有原理都与任何更复杂的基于递归的处理相关——这只是简单地适合一个 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 是一个明显的例子,你自己会遇到。

      【讨论】:

        猜你喜欢
        • 2021-01-12
        • 2017-10-01
        • 2021-02-17
        • 2020-05-04
        • 2013-05-28
        • 1970-01-01
        • 2020-08-12
        • 2022-01-03
        • 1970-01-01
        相关资源
        最近更新 更多