I'm having trouble dealing with stacks recursively in MIPS. I get the concept, but my program isn't reacting as I mean it to.
My goal is to take user input as n and print the Fibonacci number at n. What I have so far is below.
(I'm fairly certain the problem is in the actual calculation of the number in the fib function.) Thanks for any help! :)
.text
main:
# Prompt user to input non-negative number
la $a0,prompt
li $v0,4
syscall
li $v0,5
syscall
move $t2,$v0
# Call function to get fibonnacci #n
move $a0,$t2
move $v0,$t2
jal fib
move $t3,$v0
# Output message and n
la $a0,result
li $v0,4
syscall
move $a0,$t2
li $v0,1
syscall
la $a0,result2
li $v0,4
syscall
move $a0,$t3
li $v0,1
syscall
la $a0,endl
li $v0,4
syscall
# End program
li $v0,10
syscall
fib:
# Compute and return fibonacci number
beqz $a0,zero
beq $a0,1,one
sub $sp,$sp,4
sw $ra,0($sp)
sub $a0,$a0,1
jal fib
lw $ra,0($sp)
add $sp,$sp,4
sub $t8,$v0,2 # n - 2
sub $t9,$v0,1 # n - 1
add $v0,$t8,$t9 # add n-2,n-1
jr $ra # decrement/next in stack
zero:
li $v0,0
jr $ra
one:
li $v0,1
jr $ra
.data
prompt: .asciiz "Enter a non-negative number: "
result: .asciiz "F_"
result2: .asciiz " = "
endl: .asciiz "\n"
Example runs:
Enter a non-negative number: 5
F_5 = -29
Enter a non-negative number: 6
F_6 = -61
Correct runs:
Enter a non-negative number: 5
F_5 = 5
Enter a non-negative number: 6
F_6 = 8
Here is a properly working code:
.text
main:
# Prompt user to input non-negative number
la $a0,prompt
li $v0,4
syscall
li $v0,5 #Read the number(n)
syscall
move $t2,$v0 # n to $t2
# Call function to get fibonnacci #n
move $a0,$t2
move $v0,$t2
jal fib #call fib (n)
move $t3,$v0 #result is in $t3
# Output message and n
la $a0,result #Print F_
li $v0,4
syscall
move $a0,$t2 #Print n
li $v0,1
syscall
la $a0,result2 #Print =
li $v0,4
syscall
move $a0,$t3 #Print the answer
li $v0,1
syscall
la $a0,endl #Print '\n'
li $v0,4
syscall
# End program
li $v0,10
syscall
fib:
# Compute and return fibonacci number
beqz $a0,zero #if n=0 return 0
beq $a0,1,one #if n=1 return 1
#Calling fib(n-1)
sub $sp,$sp,4 #storing return address on stack
sw $ra,0($sp)
sub $a0,$a0,1 #n-1
jal fib #fib(n-1)
add $a0,$a0,1
lw $ra,0($sp) #restoring return address from stack
add $sp,$sp,4
sub $sp,$sp,4 #Push return value to stack
sw $v0,0($sp)
#Calling fib(n-2)
sub $sp,$sp,4 #storing return address on stack
sw $ra,0($sp)
sub $a0,$a0,2 #n-2
jal fib #fib(n-2)
add $a0,$a0,2
lw $ra,0($sp) #restoring return address from stack
add $sp,$sp,4
#---------------
lw $s7,0($sp) #Pop return value from stack
add $sp,$sp,4
add $v0,$v0,$s7 # f(n - 2)+fib(n-1)
jr $ra # decrement/next in stack
zero:
li $v0,0
jr $ra
one:
li $v0,1
jr $ra
.data
prompt: .asciiz "This program calculates Fibonacci sequence with recursive functions.\nEnter a non-negative number: "
result: .asciiz "F_"
result2: .asciiz " = "
endl: .asciiz "\n"
Hope to be usefull
Adel Zare
adel.zare.63 [at] gmail [dot] com
You appear to have misunderstood the algorithm (or just implemented it incorrectly). What you're doing is this:
int fib(int n) {
if (n == 0)
return 0;
else if (n == 1)
return 1;
int ret = fib(n - 1);
return (ret - 2) + (ret - 1);
}
What you should be doing is this:
int fib(int n) {
if (n == 0)
return 0;
else if (n == 1)
return 1;
return fib(n - 1) + fib(n - 2);
}
Related
I want to write a program that calculates the square of n using recursion based on the equation n^2 = (n - 1)^2 + 2(n - 1) + 1 But I don't know how to write the nonbasecase: part. Can anyone help?
A python program would be
def square(n) {
if (n==0):
return 0
else:
return square(n-1) + 2*(n-1) + 1
}
Here is what I got so far.
start:
li $a0, 0x0003 #$a0 contains the number to be squared
jal square # recursive call
square:
subi $sp, $sp, 8 # decrement the stack pointer $sp
sw $ra, 4($sp) # push the return address register $ra
sw $a0, 0($sp) # push argument register $a0
li $t0, 0x0001 # load $t0 with 1 as part of test for base case
bne $a0, $t0, nonbasecase # branch if not the base case
li $v0, 0x0001 # return base result in $v0
addi $sp, $sp 8 # recover stack space
jr $ra # jump to return address in $ra
nonbasecase:
#not sure how to write when it is not the base case
jr $ra # jump to contents of return address register $ra
Write the function so that it inputs n2 and n and returns n2+2*n+1 and n+1.
I am fairly new to MIPS and am trying to write a code which calculates the sum of an integer which was entered by the user. I am using recursion in my code but am not sure if theres an easier way to do this. My code runs fairly well for the most part however it keeps adding 1 to the final sum. For example, sum of 10 is 55 but it gives me 56.
.data
#messages
sumMessage: .asciiz "\Enter a number to find its Sum: "
sumMessage1: .asciiz "\nSum is: "
sumInput: .word 0
sumAns: .word 0
.text
.globl main
main:
#read promtMessage
li $v0, 4
la $a0, sumMessage
syscall
#take input
li $v0,5
syscall
sw $v0, sumInput#storing input
#call sumCalc function
lw $a0, sumInput
jal sumCalc
sw $v0, sumAns#returns value from function
#display sum
li $v0, 4
la $a0, sumMessage1
syscall
li $v0, 1
lw $a0, sumAns
syscall
#end main
li $v0, 10
syscall
#sumCalc Function
.globl sumCalc
sumCalc:
subu $sp, $sp, 8
sw $ra, ($sp)#storing value of returning address in the stack
sw $s0, 4($sp)#4 bites apart from the value stored above in the stack
#base case
li $v0, 1
beq $a0, 0, exit
#find factorial n-1
move $s0, $a0
sub $a0, $a0, 1
jal sumCalc
add $v0, $s0, $v0
exit:
lw $ra, ($sp)
lw $s0,, 4($sp)
addu $sp, $sp, 8
jr $ra
Any help would be appreciated!
Using recursion here makes the processing cumbersome and of little interest because we can calculate the sum directly. The sum of an integer is given to us using the following mathematical formula: n * (n + 1) / 2 or else n * (n + 1) then a right shift which is comparable to a division by 2.
.data
#messages
sumMessage: .asciiz "\Enter a number to find its Sum: "
sumMessage1: .asciiz "\nSum is: "
sumInput: .word 0
sumAns: .word 0
.text
.globl main
main:
#read promtMessage
li $v0, 4
la $a0, sumMessage
syscall
#take input
li $v0,5
syscall
sw $v0, sumInput#storing input
#call sumCalc function
lw $a0, sumInput
jal sumCalc
sw $s2, sumAns#returns value from function
#display sum
li $v0, 4
la $a0, sumMessage1
syscall
li $v0, 1
lw $a0, sumAns
syscall
#end main
li $v0, 10
syscall
#sumCalc Function
.globl sumCalc
sumCalc:
subu $sp, $sp, 8
sw $ra, ($sp)#storing value of returning address in the stack
sw $s0, 4($sp)#4 bites apart from the value stored above in the stack
li $s2,1 # storing the final result
move $s3,$v0
addi $s3,$s3,1 # $s3 = $v0+1
mul $s2,$v0,$s3 # $s2 = $v0 * ($v0 +1)
div $s2,$s2,2 # $s2 = $s2/2
exit:
lw $ra, ($sp)
lw $s0,4($sp)
addu $sp, $sp, 8
jr $ra
def count_partitions(n, m):
if n == 0:
return 1
elif n < 0:
return 0
elif m == 0:
return 0
else:
l = count_partitions(n, m-1) + count_partitions(n-m, m)
return l
Trying to convert this python code into MIPS assembly. My assembly code does its job but after it gets to the right answer, it continues and gets to absurd numbers.
I tried debugging with mars.jar and found out that my stack pointer didnt get updated at one point. Thanks a lot.
My code:
.data
prompt1: .asciiz "\Enter an integer to partition (n): "
prompt2: .asciiz "\Enter an integer for size of the partition (m): "
default: .asciiz "\nstuff "
.text
main:
la $a0, prompt1
li $v0,4
syscall
li $v0, 5
syscall
move $t0, $v0 # $t0 = n
la $a0, prompt2
li $v0,4
syscall
li $v0, 5
syscall
move $t1, $v0 # $t1 = m
add $a0, $t0, $zero
add $a1, $t1, $zero
addi $sp,$sp,-4
sw $ra,0($sp)
jal count_partitions
lw $ra,0($sp)
addi $sp,$sp,4
move $a0,$v0
li $v0, 1
syscall #prints the default
li $v0, 10
syscall
count_partitions:
addi $sp,$sp,-16
sw $s1,12($sp)
sw $a1,8($sp)
sw $a0,4($sp)
sw $ra,0($sp)
bne $a0,$zero,case1
addi $v0,$v0,1
j return
case1:
slti $t0,$a0,0
beq $t0,$zero,case2
j return
case2:
bne $a1,$zero,case3
j return
case3:
addi $a1,$a1,-1
jal count_partitions
addi $t7,$zero,1
mult $v0,$t7
mflo $s1
addi $a1,$a1,1
sub $a0,$a0,$a1
jal count_partitions
addi $t7,$zero,1
mult $v0,$t7
mflo $t2
add $v0,$s1,$t2
return:
lw $ra,0($sp)
lw $a0,4($sp)
lw $a1,8($sp)
lw $s1,12($sp)
addi $sp,$sp,16
jr $ra
So I understand the logic behind how to calculate the sum of digits. I was just wondering whether this recursive function is correct. Assume that the user already entered the number which he or she wants the digit sum for and is stored in $v0.
Sum2:
li $s0, 0
move $a1, $v0
li $s1, 0
li $s2, 10
# I am adjusting the stack frame size to store 3 words
addi $sp, $sp,-12
# These are the sum value, the return address, and the number
sw $s1, 0($sp)
sw $ra, 4($sp)
sw $a1, 8($sp)
Loop2: bne $s0, $a1, SUM3
move $a0, $s1
li $v0, 1
syscall
lw $s1, 0($sp)
lw $ra, 4($sp)
lw $a1, 8($sp)
addi $sp, $sp 12
jr $ra
SUM3:
div $t0, $a1, $s2
mfhi $t0
add $s1, $s1, $t0
div $t1, $a1, $s2
mflo $a1
j Loop2
If the logic isn't clear I am first checking to see if the number doesn't equal zero and if it doesn't I will then get the modulus of the number divided by 10 and add it to the sum which is initially 0 and then divide the user input number by 10 and continue to call the function till the number eventually becomes zero. I also had one quick last question. In Mips would a recursive function or iterative function execute faster?
Your implementation corresponds to something like this:
int sum_digits(int n) {
int res = 0;
while (n != 0) {
res += n % 10;
n /= 10;
}
return res;
}
Actually you're just printing the result rather than returning it, but that's beside the point. It's clearly an iterative function.
A recursive implementation would look something like this:
int sum_digits(int n) {
return (n >= 10) ? ((n % 10) + sum_digits(n / 10)) : (n % 10);
}
I'll leave it to you to translate that into MIPS assembly now that you know what the algorithm looks like.
Proper implementation of recursion to do sum of digits:
.data
n: .word 1965
s: .word 0
.text
main:
lw $t0,n
addi $t1,$zero,10
add $t4,$zero,$zero #the result
recursion:
div $t0,$t1 #n/10 and n%10
mflo $t0 #n=n/10
mfhi $t3 #digit=n%10
add $t4,$t4,$t3 #s=s+digit
bne $t0,$zero,recursion #if n!=0
end:
sw $t4,s
li $v0,10
syscall
I am trying to find the GCD of two numbers with recursion.
This code is what I've done so far but apparently it gets into an infinite loop and i can't understand why and how to solve this problem.
I would appreciate some help
.data
string1: .asciiz "Enter the first number: "
string2: .asciiz "Enter the second number: "
string3: .asciiz "GCD is : "
.text
li $v0,4
la $a0,string1
syscall
li $v0, 5
syscall
add $s0,$v0,$zero #s0 = first number
li $v0,4
la $a0,string2
syscall
li $v0, 5
syscall
add $s1,$v0,$zero #s1= second number
slt $t0,$s0,$s1
beq $t0,$zero,L # if first number < second number , swap
add $t1,$s0,$zero
add $s0,$s1,$zero
add $s1,$t1,$zero
L:
add $a0,$s0,$zero # put first number in $a0 as input argument
add $a1,$s1,$zero # put second number in $a1 as input argument
jal GCD
GCD:
addi $sp,$sp,-4
sw $ra,0($sp)
bne $a1,$zero,L1 # base case condition
add $v0,$zero,$a0 # if base case is true
addi $sp,$sp,4
jr $ra
L1:
div $a0,$a1
add $a0,$a1,$zero
mfhi $a1
jal GCD
lw $ra,0($sp)
addi $sp,$sp,4
jr $ra
add $s3,$v0,$zero # put result in $s3
li $v0,4
la $a0,string3
syscall
li $v0,1
add $a0,$s3,$zero
syscall
So your program starts execution at the beginning of the .text segment and continues straight onto the line jal GCD after the L label.
Next your program jumps to the GCD label where it executes until the jr $ra which makes it return to the jal which has as its next instruction of course GCD. This causes the infinite loop.
So the problem here is that you have inserted the GCD function in the middle of your main function. Generally speaking it is always an error to jal to the next line.
So you should move the definition of GCD elsewhere and consider what it is that you would like to run after returning from this function.