美文网首页
ruby递归优化 - 尾递归、增加栈

ruby递归优化 - 尾递归、增加栈

作者: 我要走多远 | 来源:发表于2016-12-11 11:13 被阅读267次

递归很好用,但容易导致栈溢出(SystemStackError: stack level too deep)。
简单的解决方案有两个,一个是把ruby的stack size调大,一个是用尾递归。

Stack level too deep

def factorial(n)
  raise InvalidArgument, "negative input given" if n < 0
  if n == 0
    1
  else
    factorial(n - 1) * n
  end
end

输入比较小的时候,代码工作正常

 irb> factorial(1_000).to_s.size
 => 2568

但当我们把输入变大的时候,就会报错

 irb> factorial(100_000).to_s.size
 SystemStackError: stack level too deep

解决方案 - 增加栈大小

我们可以增加ruby vm的栈大小。只要设置RUBY_THREAD_VM_STACK_SIZE这个环境变量就可以了。

export RUBY_THREAD_VM_STACK_SIZE=50000000

我们还可以通过RubyVM::DEFAULT_PARAMS这条命令查看原有的值。

不过,这种方式也不能完全解决问题的,更好的方式是,使用尾递归。

尾递归

ruby默认是不支持尾递归的,首先我们要先开启配置。

RubyVM::InstructionSequence.compile_option = {
  tailcall_optimization: true,
  trace_instruction: false
}

尾递归的实现如下:

def factorial_by_tail_call(n, accumulator = 1)
  raise InvalidArgument, "negative input given" if n < 0

  return accumulator if n == 0
  return factorial_by_tail_call(n - 1, accumulator * n)
end

尾递归为什么没有溢出?

简单来说在factorial内, factorial(n - 1) * n 必须要有n才能计算出结果,所以当前这次执行(procedure call)必须要存在内存里。
factorial_by_tail_call却不一样,factorial_by_tail_call(n - 1, accumulator * n)不依赖任何其他变量,可以直接被执行,其实没必要存在内存里,所以可以被优化。

语言对尾递归的支持情况

首先尾递归优化需要解释器的支持。

ruby也是后来才支持的,但需要手动开启。

java不支持,clojure虽然不支持,但用recur达到了同样的效果。

最后,上个世纪的lisp是支持尾递归的!

相关文章

  • ruby递归优化 - 尾递归、增加栈

    递归很好用,但容易导致栈溢出(SystemStackError: stack level too deep)。简单...

  • 9. 递归函数

    使用递归函数需要注意防止栈溢出解决递归调用栈溢出的方法是通过尾递归优化遗憾的是,大多数编程语言没有针对尾递归做优化...

  • 尾递归优化

    “尾递归优化”的含义是:如果递归函数属于尾递归,那么运行时会优化其调用过程。优化主要针对调用栈,将多层调用,转化为...

  • 1

    #函数 ##递归函数容易,栈溢出,这个时候可以用*尾递归*优化,尾递归的意思就是说在递归函数末尾引用本函数的时候,...

  • python学习

    1:尾递归 解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊...

  • Kotlin语言(九):特性

    1、尾递归优化 尾递归:函数在调用自己之后没有再执行其他任何操作就是尾递归 尾递归优化的原理就是将递归转换成迭代,...

  • 什么是尾调用?什么是尾递归?尾调用的优化?尾递归优化?

    尾调用优化 尾递归(尾调用优化)

  • Python学习之路(递归函数)

    函数之 递归函数 小结 使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。针对尾递归优化的语言可以通...

  • 第2模块第1章2829递归的作用尾递归优化

    尾递归优化 def cal(n): print(n) return cal(n+1) cal(1) 尾递归优化并不...

  • 2018-07-28

    递归函数以及尾递归优化: #利用递归函数计算阶乘 ... #N! = 1 * 2 * 3 * 4 * ... * ...

网友评论

      本文标题:ruby递归优化 - 尾递归、增加栈

      本文链接:https://www.haomeiwen.com/subject/stfpmttx.html