【问题标题】:Recursion in NASM: FibonacciNASM 中的递归:斐波那契
【发布时间】:2019-04-23 18:31:25
【问题描述】:

我很难让递归工作。好吧,递归 n!阶乘计算器并不难,花了我大约半天的时间。

   mov eax, [input]
   call factorialator

   jmp quit
 ;   
factorialator:
   cmp eax, 0
   je return
   push eax
   dec eax
   call factorialator
  ;
   pop eax
   imul ebx, eax
   ret
;
return:
   mov ebx, 1
   ret

现在,该函数以 n = n-1 调用自身,并每次将 n 推入直到 n = 0,然后将它们全部相乘。 简单易懂

但是现在,我必须使用 (n-1) AND (n-2) 调用函数,我无法想象这将如何工作,因为我必须管理返回地址、堆栈和值。我所知道的,每次当它减去 1 或 2 并且结果为 1 时,它应该包含一个计数器,然后它会给我们结果。

所以返回 n-1 直到 n-1 = 1,在这种情况下返回 n-2,然后再次返回 n-1。我只是如此感到困惑,并且已经为此苦苦挣扎了 2 天。

感谢您的帮助,谢谢!

【问题讨论】:

  • 首先用高级语言(或伪代码)编写代码,使用临时命名变量。这样你在 asm 版本中需要做什么会更清楚。

标签: recursion assembly x86 nasm fibonacci


【解决方案1】:

原理是一样的。在阶乘情况下,您暂时保存N,因为您稍后需要将fact(N-1) 乘以。
在斐波那契数列情况下,您还暂时保存N(或N-1),因为您稍后需要它来计算N-2,以便计算fib(N-2)

x86 实现可能如下所示:

fib:
    cmp eax,1       ; Base case?
    jbe done        ; Yes => return n
    dec eax
    push eax        ; Save n-1 on the stack
    call fib        ; Calculate fib(n-1)
    xchg eax,[esp]  ; Place fib(n-1) on the stack, while retrieving n-1 into eax
    dec eax
    call fib        ; Calculate fib(n-2)
    add eax,[esp]   ; fib(n-2) + fib(n-1)
    add esp,4       ; "Undo" the push operation
done:
    ret

【讨论】:

  • 注意xchg eax,[esp] 有一个隐含的lock 前缀,因此比使用单独的加载/存储指令慢很多(使用像mov edx,[esp] / mov [esp],eax / @ 这样的暂存寄存器987654332@)。当然,如果您完全关心效率,您会在 O(n) 时间内使用 add eax,edx / add edx,eax 迭代计算 Fib(n) 而不是 O(Fib(n))时间,以及较低的常数因子。但总的来说,将xchg 与 mem 一起使用是很危险的。
猜你喜欢
  • 2013-10-13
  • 2010-12-03
  • 2014-04-02
  • 2017-12-12
  • 2017-09-10
  • 2017-11-18
  • 2014-01-08
  • 2011-12-14
相关资源
最近更新 更多