使用递归程序在NASM中的第n个斐波纳契数 - [ASSEMBLY]

时间:2018-02-26 13:35:06

标签: recursion assembly nasm fibonacci

以下是我用来解决问题的代码:

%include "io.mac"

section .data
    msg1 db "Enter a positive number: ",0
    msg2 db "fibonacci number is: ",0
    space db " ",0

section .bss

section .text
    global _start
_start:
    PutStr msg1
    GetLInt EBX
    mov EDX,EBX
    cmp EBX,1
    jge result
    jmp _start
result:
    PutLInt EBX
    PutStr space
    PutStr msg2
    call fibo
    PutLInt EAX
    nwln
    .EXIT

fibo:
    cmp EBX,2
    jg fibo_helper
    mov EAX,1
    ret

fibo_helper:
    dec EBX
    call fibo
    mov ECX,EAX
    dec EBX
    call fibo
    ADD EAX,ECX
    ret    

但是这段代码只为n <5而输出正确的方法。其余只输出n-1。

有人可以帮我吗?

1 个答案:

答案 0 :(得分:2)

你的算法是递归的,但是你使用寄存器来存储C中的局部变量等中间值,因此大致会发生这种情况(从头部写入,使用调试器和单步执行指令来验证我是否正确):

- fibo(ebx = 5): jumps to fibo_helper, ebx = 4 (--ebx), call fibo(ebx=4)
  - fibo(ebx=4): -> helper -> call fibo(ebx=3)
    - fibo(ebx=3): -> helper -> call fibo(ebx=2)
      - fibo(ebx=2), eax=1, ret
    - in helper after first call: ecx=1, --ebx, call fibo(ebx=1)
      - fibo(ebx=1), eax=1, ret
    - eax = 1 + ecx(1) = 2, ret
  - in helper after first call: ecx=2, --ebx, call fibo(ebx=0)
    - fibo(ebx=0), eax=1, ret
  - eax = 1 + ecx(2) = 3, ret
- in helper after first call: ecx=3, --ebx, call fibo(ebx=-1)
  - fibo(ebx=-1), eax=1, ret
- eax = 1 + ecx(3) = 4, ret

寄存器就像“超级全局”,如果你想创建递归算法,你必须保留所需的所有值(动态地,最有可能在堆栈上),这必须在递归调用中存活。

谷歌的一些工作x86的例子(而不是例子,看看即使这样简单的实现可能会有所不同),必须有大量的这些东西,即使在这里也是如此...并检查一些堆栈使用与递归教程以获得更好想法如何/何时保留价值观。

编辑:如果你足够聪明并且可以自由地为递归函数设计自定义调用约定,那么通常可以通过巧妙的设计来最小化堆栈内存需求。

在这种情况下,您可以通过这种方式设计fibo函数,它将值添加到eax(运行总和),在ebx = n中输入,这将是保留(返回未修改的值)。因此eax将作为函数的输入和输出。

然后,您必须先将eax清零,然后再致电:

    ... set ebx to "n" ...
    xor  eax,eax
    call fibo

递归函数本身将是:

fibo:
    cmp  ebx,2
    jg   fibo_helper
    inc  eax      ; sum += 1 (fib(1) = fib(2) = 1)
    ret
fibo_helper:
    dec  ebx
    call fibo     ; sum += fib(n-1)
    dec  ebx
    call fibo     ; sum += fib(n-2)
    add  ebx,2    ; restore ebx to original value
    ret

然后堆栈存储器仅用于跟踪call+ret对,即递归深度,不需要使用它来保存值。