Recursion Mips中的Fibonacci递归函数

Recursion Mips中的Fibonacci递归函数,recursion,mips,qtspim,Recursion,Mips,Qtspim,我试图练习递归在Mips中的工作原理。所以我试着写一个斐波那契函数。 起初,我有addi$a0,$a0,n来编写一个通用的解决方案,但我认为如果我想在Qtspim中检查我的结果,也许我需要添加一个实数作为参数。如果代码背后的想法是错误的,我不需要完整的答案,但需要一些帮助,以便在Qtspim中运行它,并自己找到我的错误(逻辑错误) 这是我的代码: .globl main .text main: addi $a0, $a0, 4 fib: addi $sp, $sp, -8 s

我试图练习递归在Mips中的工作原理。所以我试着写一个斐波那契函数。 起初,我有
addi$a0,$a0,n
来编写一个通用的解决方案,但我认为如果我想在Qtspim中检查我的结果,也许我需要添加一个实数作为参数。如果代码背后的想法是错误的,我不需要完整的答案,但需要一些帮助,以便在Qtspim中运行它,并自己找到我的错误(逻辑错误)
这是我的代码:

.globl main
    .text
    main:
addi $a0, $a0, 4


fib:
addi $sp, $sp, -8
sw $ra, 4($sp) 
sw $a0, 0($sp) 
slti $t0, $a0, 1
beq $t0, 1, L2  #if n<1     
beq $a0, 1, L2  # if n=1
beq $t0, 0, L1 # if n>1

#what to do when n<=1
L2:
addi $v0, $v0, 1 
jr $ra 

#what to do when n>1
L1: 
addi $a0, $a0, -1 
jal fib
lw $a0, 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 8
lw $t1, 0($v0)
add $v0, $t1, $v0
jr $ra

li $v0,10
syscall
.globl main
.文本
主要内容:
addi$a0,$a0,4
小谎:
附加$sp,$sp,-8
西南$ra,4($sp)
sw$a0,0($sp)
slti$t0,$a0,1
如果n1,则beq$t0,1,L2
#当n1时该怎么办
L1:
addi$a0,$a0,-1
日本航空公司
lw$a0,0($sp)
lw$ra,4$sp
附加$sp,$sp,8
lw$t1,0($v0)
添加$v0、$t1、$v0
jr$ra
李$v0,10
系统调用
我收到一条错误消息,如下所示: 数据/堆栈读取中的地址错误:0x00000000
    .text
    main:
addi $a0, $a0, 4
#### you've place fib inline inside main,
#### you should have all of main here, and "call" fib using jal instruction  
#### and the syscall for exit goes up here as well

fib:
addi $sp, $sp, -8        # you will want one more word of stack space
sw $ra, 4($sp) 
sw $a0, 0($sp) 
slti $t0, $a0, 1            # i would have use 2 here instead of 1
beq $t0, 1, L2  #if n<1     # this is ok, but better to use bne $t0, $0, L2
beq $a0, 1, L2  # if n=1    # and then this would not be needed
beq $t0, 0, L1 # if n>1     # this doesn't need to be conditional, if the program reaches here then L1 is the thing to do next.

#what to do when n<=1
L2:
addi $v0, $v0, 1            # here you want to return just 1 not v0+1
jr $ra 

#what to do when n>1
L1: 
addi $a0, $a0, -1 
jal fib                        # fib(n-1), good
lw $a0, 0($sp)                 # this reloads $a0 the original n
lw $ra, 4($sp)
addi $sp, $sp, 8
lw $t1, 0($v0)                 # after a call to fib $v0 holds fib(n)
                               # an integer value but you're treating it like a pointer and dereferencing it
add $v0, $t1, $v0              # here doing fib(n-1) + n
                               # you want fib(n-1) + fib(n-2) instead
                               # so you're missing a fib(n-2)
jr $ra

li $v0,10                  # this is part of main, so move it to where main is
syscall                    # realize that code located here is unreachable (aka dead)
                           # anything after an unconditional branch (here the jr $ra just above)
                           # and without a label is very suspicious as unreachable
主要内容: addi$a0,$a0,4 ####你已经把小谎放在主管道里面了, ####你应该把所有的main都放在这里,并使用jal指令“呼叫”fib ####退出的系统调用也在这里 小谎: addi$sp,$sp,-8#您还需要一个字的堆栈空间 西南$ra,4($sp) sw$a0,0($sp) slti$t0,$a0,1#我在这里用2代替1 beq$t0,1,L2#如果n1#这不需要有条件,如果程序到达这里,那么L1是下一步要做的事情。 #当n1时该怎么办 L1: addi$a0,$a0,-1 日本航空公司fib#fib(n-1),很好 lw$a0,0($sp)#这将重新加载原始n的$a0 lw$ra,4$sp 附加$sp,$sp,8 lw$t1,0($v0)#在调用fib$v0后保持fib(n) #一个整数值,但你把它当作一个指针来处理,然后去引用它 加上$v0,$t1,$v0#在这里做fib(n-1)+n #你想要fib(n-1)+fib(n-2)来代替 #所以你漏掉了一个小谎(n-2) jr$ra li$v0,10#这是main的一部分,所以将其移动到main所在的位置 syscall#意识到此处的代码是不可访问的(又称死代码) #无条件分支后的任何内容(这里是jr$ra,就在上面) #而没有标签是非常可疑的,因为无法接近 更新,一些改进的(我希望)代码

.globl main
.文本
主要内容:
addi$a0,$a0,4
日本航空公司
李$v0,10
系统调用
小谎:
附加$sp,$sp,-8
西南$ra,4($sp)
sw$a0,0($sp)
slti$t0,$a0,2
beq$t0,1,L2
#当n1时该怎么办
L1:
addi$a0,$a0,-1#a0->n-1
日本航空公司fib#fib(n-1)
lw$a0,0($sp)#从内存地址0($sp)加载字以注册$a0
lw$ra,4($sp)#从内存地址4($sp)加载字以注册$ra
附加$sp,$sp,8
在寄存器$t1中添加$t1、$零、$v1#存储当前$v1
添加$v0、$t2、$v0#v0 n+1=v0 n+v0 n-1
在$t2中添加$t2、$t1、$零#保存先前的v1值

非常感谢您的回答,当我写
addi$v0,v0,1时,我有很多问题要问您,因为(我认为)$v0是以零初始化的,我认为我确实返回了1或是错误的?如果它有效,这是一个奇迹和糟糕的编程实践,那么为什么不将其更改为正好返回1。好的,请重新阅读我所有的评论,并对每个评论都做些什么。我没有得到关于“死代码”的部分。你是说我应该把
li$v0,10
放在fib之前?
    .globl main
.text
main:
addi $a0, $a0, 4
jal fib 
li $v0, 10
syscall 

fib:
addi $sp, $sp, -8
sw $ra, 4($sp) 
sw $a0, 0($sp) 
slti $t0, $a0, 2
beq $t0, 1, L2      

#what to do when n<=1
L2:
addi $v0, $v0, 1 
jr $ra 

#what to do when n>1
L1: 
addi $a0, $a0, -1  # a0 -> n-1
jal fib   # fib(n-1)
lw $a0, 0($sp) #load word from memory adress 0($sp) to register $a0
lw $ra, 4($sp)  #load word from memory adress 4($sp) to register $ra
addi $sp, $sp, 8 
add $t1, $zero, $v1  # in register $t1 store current $v1
add $v0, $t2, $v0  # v0_ n+1 =v0 _n + v0_n-1
add $t2, $t1, $zero  # in $t2 save the previous value of v1 

   
.data
prompt: .ascii "Fibonacci Program\n"
.asciiz "Enter N value: "
results: .asciiz "\nFibonacci of N = "
n: .word 0
answer: .word 0

.text
.globl main
.ent main
main:

# Read n value from user
li $v0, 4 # print prompt string
la $a0, prompt
syscall

li $v0, 5 # read N (as integer)
syscall
sw $v0, n

# Call Fibonacci function.
lw $a0, n
jal fib
sw $v0, answer

# Display result
li $v0, 4 # print prompt string
la $a0, results
syscall
li $v0, 1 # print integer
lw $a0, answer
syscall

# Done, terminate program.
li $v0, 10 # terminate
syscall # system call
.end main

# Fibonacci function
# Recursive definition:
# = 0 if n = 0
# = 1 if n = 1
# = fib(n-1) + fib(n-2) if n > 2

# Arguments
# $a0 - n
# Returns
# $v0 set to fib(n)

.globl fib
.ent fib

fib:
subu $sp, $sp, 8
sw $ra, ($sp)
sw $s0, 4($sp)
move $v0, $a0 # check for base cases
ble $a0, 1, fibDone
move $s0, $a0 # get fib(n-1)
sub $a0, $a0, 1
jal fib
move $a0, $s0
sub $a0, $a0, 2 # set n-2
move $s0, $v0 # save fib(n-1)
jal fib # get fib(n-2)
add $v0, $s0, $v0 # fib(n-1)+fib(n-2)
fibDone:
lw $ra, ($sp)
lw $s0, 4($sp)
addu $sp, $sp, 8
jr $ra
.end fib