Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 为什么我的递归函数在R中如此缓慢?_Algorithm_R_Optimization_Recursion_Fibonacci - Fatal编程技术网

Algorithm 为什么我的递归函数在R中如此缓慢?

Algorithm 为什么我的递归函数在R中如此缓慢?,algorithm,r,optimization,recursion,fibonacci,Algorithm,R,Optimization,Recursion,Fibonacci,下面的运行大约需要30秒,而我希望它几乎是即时的。我的代码有问题吗 x <- fibonacci(35); fibonacci <- function(seq) { if (seq == 1) return(1); if (seq == 2) return(2); return (fibonacci(seq - 1) + fibonacci(seq - 2)); } x:-)因为你使用指数算法!!!因此,对于斐波那契数N,它必须调用函数2^N次,即2^35

下面的运行大约需要30秒,而我希望它几乎是即时的。我的代码有问题吗

x <- fibonacci(35);

fibonacci <- function(seq) {
    if (seq == 1) return(1);
    if (seq == 2) return(2);
    return (fibonacci(seq - 1) + fibonacci(seq - 2));
}
x:-)因为你使用指数算法!!!因此,对于斐波那契数N,它必须调用函数2^N次,即2^35,这是一个非常好的数字….:-)

使用线性算法:

fib = function (x)
{
        if (x == 0)
                return (0)
        n1 = 0
        n2 = 1
        for (i in 1:(x-1)) {
                sum = n1 + n2
                n1 = n2
                n2 = sum
        }
        n2
}

抱歉,编辑:指数递归算法的复杂性不是O(2^N),而是O(fib(N)),因为:-)这是一个很好的注释:-)

,因为您使用的是其中一个


其复杂性为
O(斐波那契(n))
=
O((黄金比率)^n)
黄金比率为1.618033987498948482…

Patrick Burns给出了一个用
local()在R中进行记忆的方法示例<代码> >代码> > P>这正好提供了一个很好的插件机会,这使得我们可以很容易地将C++函数添加到R.<
因此,在稍微修改代码、使用软件包(将短代码段轻松编译、加载和链接为可动态加载的函数)以及计时和比较函数之后,我们的性能提高了700倍:

R> print(res)
        test replications elapsed relative user.self sys.self
2 fibRcpp(N)            1   0.092    1.000      0.10        0
1    fibR(N)            1  65.693  714.054     65.66        0
R> 
在这里,我们看到了92百万秒与65秒的流逝时间,相对比率为714。但是现在所有人都告诉你不要直接在R。。。。代码如下

## inline to compile, load and link the C++ code
require(inline)

## we need a pure C/C++ function as the generated function
## will have a random identifier at the C++ level preventing
## us from direct recursive calls
incltxt <- '
int fibonacci(const int x) {
   if (x == 0) return(0);
   if (x == 1) return(1);
   return (fibonacci(x - 1)) + fibonacci(x - 2);
}'

## now use the snipped above as well as one argument conversion
## in as well as out to provide Fibonacci numbers via C++
fibRcpp <- cxxfunction(signature(xs="int"),
                   plugin="Rcpp",
                   incl=incltxt,
                   body='
   int x = Rcpp::as<int>(xs);
   return Rcpp::wrap( fibonacci(x) );
')

## for comparison, the original (but repaired with 0/1 offsets)
fibR <- function(seq) {
    if (seq == 0) return(0);
    if (seq == 1) return(1);
    return (fibR(seq - 1) + fibR(seq - 2));
}

## load rbenchmark to compare
library(rbenchmark)

N <- 35     ## same parameter as original post
res <- benchmark(fibR(N),
                 fibRcpp(N),
                 columns=c("test", "replications", "elapsed",
                           "relative", "user.self", "sys.self"),
                 order="relative",
                 replications=1)
print(res)  ## show result

如果您确实希望返回斐波那契数,并且没有使用此示例来探索递归的工作原理,那么您可以使用以下方法非递归地解决它:

fib = function(n) {round((1.61803398875^n+0.61803398875^n)/sqrt(5))}

具有线性成本的递归实现:

fib3 <- function(n){
  fib <- function(n, fibm1, fibm2){
    if(n==1){return(fibm2)}
    if(n==2){return(fibm1)}
    if(n >2){
      fib(n-1, fibm1+fibm2, fibm1)  
    }
  }
fib(n, 1, 0)  
}
此解决方案可以使用
ifelse
进行矢量化:

fib4 <- function(n){
    fib <- function(n, fibm1, fibm2){
        ifelse(n<=1, fibm2,
          ifelse(n==2, fibm1,
            Recall(n-1, fibm1+fibm2, fibm1)  
          ))
    }
    fib(n, 1, 0)  
}

fib4(1:30)
##  [1]      0      1      1      2      3      5      8
##  [8]     13     21     34     55     89    144    233
## [15]    377    610    987   1597   2584   4181   6765
## [22]  10946  17711  28657  46368  75025 121393 196418
## [29] 317811 514229
fib4因为这里已经提到的是一个参考实现:

fib <- function(n) {
  if (n < 2) return(1)
  fib(n - 2) + fib(n - 1)
}
system.time(fib(35))
##    user  system elapsed 
##   36.10    0.02   36.16

library(memoise)
fib2 <- memoise(function(n) {
  if (n < 2) return(1)
  fib2(n - 2) + fib2(n - 1)
})
system.time(fib2(35))
##    user  system elapsed 
##       0       0       0


fib记忆在哪里?除了实现上面提到的更好的算法外,您还可以尝试Radford Neal一直在开发的一些R补丁。我不确定你的问题,但你确定这是正确的实现。当然,您的代码将生成
1,2,3,5,8,
,而正确的序列是
0,1,1,2,3,5,8,
?不熟悉记忆以及如何在R中实现它。我正在实现此处指定的斐波那契包
gmp
具有函数
fibnum
,以任意精度计算斐波那契数。使用标准的
double
,您最多只能得到
n=55
左右。好吧,这是个好主意。地狱和记忆,听起来真的很神奇。我们通常称之为全局变量:-),但无论如何,我没有想到在线性时间中使用递归!很好的说明。后期添加:有几个选项可供记忆:请参阅。@hadley:在此处添加此选项作为答案:嗯,Rcpp。。。看起来真的很好很简单!!不错;-)您似乎还试图证明指数算法的合理性;)嗯,编译代码的速度是92毫秒,它没有实现指数算法,即使是在速度很快的计算机上。编译器必须以某种巧妙的方式进行优化。我认为这不是一个公平的测试。内联包是由R驱动的,因此得到了标准的gcc/g++选项。所以我称之为公平测试:因为它显示了编译程序可以为你做,如果你把R三的内衬翻译成C++三的内衬。在任何情况下,如果你真的想学习asm代码,你都可以。呵呵,都是真的。但它并没有说明R在其解释器中是否以及在何处存在低效。这与我们更相关,我们认为从R调用C就是承认R从根本上是一种坏语言(或者,至少是一种从根本上坏掉的S实现)。恕我直言,这是胡说八道。任何给定的系统都有一个特殊的弱点。我的观点是,我们可以通过结合相关的优势来构建更好的系统——甚至可以像这个例子所显示的那样轻松地做到这一点——而不是因为这些劣势而紧张。例如,看看钱伯斯去年秋天在斯坦福大学的演讲:它总是关于语言和工具的结合。我的拙劣观点是RCPP帮助你把C++和R的更好部分结合起来,但是你当然可以自由地把R扔进垃圾箱,使用本周流行的任何东西。祝你好运。这个函数精确到
n=55
@MatthewLundberg一点也不!我还将初始条件更改为
n,1,0
,使其在数学上正确,但这并不会改变运行时间或原始代码的含义。@MatthewLundberg nice,我还喜欢
回忆
编辑,如果您在
备忘录
包的功能上添加一两句话,它会很有用,一般来说。
> system.time(fibonacci(35))
  usuário   sistema decorrido 
   14.629     0.017    14.644 
> system.time(fib3(35))
  usuário   sistema decorrido 
    0.001     0.000     0.000
fib4 <- function(n){
    fib <- function(n, fibm1, fibm2){
        ifelse(n<=1, fibm2,
          ifelse(n==2, fibm1,
            Recall(n-1, fibm1+fibm2, fibm1)  
          ))
    }
    fib(n, 1, 0)  
}

fib4(1:30)
##  [1]      0      1      1      2      3      5      8
##  [8]     13     21     34     55     89    144    233
## [15]    377    610    987   1597   2584   4181   6765
## [22]  10946  17711  28657  46368  75025 121393 196418
## [29] 317811 514229
fib <- function(n) {
  if (n < 2) return(1)
  fib(n - 2) + fib(n - 1)
}
system.time(fib(35))
##    user  system elapsed 
##   36.10    0.02   36.16

library(memoise)
fib2 <- memoise(function(n) {
  if (n < 2) return(1)
  fib2(n - 2) + fib2(n - 1)
})
system.time(fib2(35))
##    user  system elapsed 
##       0       0       0