MIPS program for calculating n choose k using recursion - mips

I started a course of assembly and I am using MIPS as the programming language. I try to solve the problem of n choose k. Here is the code that I got so far but it always shows 1 as the result.
# Calculate n choose k
#
# n: integer value for n
# k: integer value for k
#
# Return: integer value for n choose k
.text
.globl nChooseK
nChooseK:
# Check if k is equal to 0 or k is equal to n
beq $a1, $zero, return_1
beq $a1, $a0, return_1
# Calculate n-1 choose k-1
sub $t0, $a0, 1
sub $t1, $a1, 1
jal nChooseK
move $t2, $v0
# Calculate n-1 choose k
move $a0, $a0
move $a1, $t1
jal nChooseK
move $t3, $v0
# Return the sum of the two calculations
add $v0, $t2, $t3
jr $ra
return_1:
# Return 1 if k is equal to 0 or k is equal to n
li $v0, 1
# Print the result of n choose k
.globl main
main:
li $a0, 5 # Load the value of n into $a0
li $a1, 3 # Load the value of k into $a1
#jal nChooseK # Call the nChooseK function
move $a0, $v0 # Load the result into $a0
li $v0, 1 # Set $v0 to 1 to print an integer
syscall # Print the result
li $v0, 10 # Set $v0 to 10 to exit the program
syscall # Exit the program

Your problem is most likely here:
return_1:
# Return 1 if k is equal to 0 or k is equal to n
li $v0, 1
# fallthrough into main (comment added by me). Put jr $ra here
# Print the result of n choose k
.globl main
Regardless of your input, eventually one of your recursions will have to return 1 as a base case. So, what's happening is, you're setting $v0 to 1 and going back into main. Now, that being said, I'm not sure why this doesn't result in an infinite loop, since you'd end up calling nChooseK over and over again and overflow the stack. Could be that you've commented out the jal nChooseK down at the bottom.

Related

MIPS: Infinite loop with branches

So I have a program that takes an input from the user (integer above 0) and adds up all even numbers below it to achieve a return answer (Ex: input: 7; ans: 2 + 4 + 6 = 12).
The issue with this program is that it's meant to break out of the loop based on if my 'active even variable' ($t1) > the input. Although my program never seems to properly interpret the branch and loops indefinitely until $t1 overflows (I have checked the debugger and know that the program does run the branch line every time). Below is my code:
.data
N: .word 0
Result: .word 0
.text
.globl main
initialize:
li $v0, 5 #getting arg1 from user
syscall
la $t0, N
sw $v0, 0($t0)
li $t1, 2
li $t2, 0
main:
blt $t0, $t1, fin2
fori:
add $t2, $t2, $t1 #t2 += t1
add $t1, $t1, 2 #t1 += 2
slt $t5, $t1, $t0
bne $t5, $zero, fori
fin:
li $v0,1 #prints return value
move $a0, $t2
syscall
li $v0, 10
syscall
fin2:
li $v0,1 #prints return value
move $a0, $zero
syscall
li $v0, 10
syscall
So I don't know if you NEED to be using word storage and such, but really you were just over complicating it in doing so. All you needed was a simple loop which has a counter that increments by 2, checks if it is larger than the initial value, and then add that overall value to the result
.text
.globl main
initialize:
li $v0, 5 # Getting arg1 from user
syscall # System call
move $t0, $v0 # Store the input value in $t0
li $t1, 0 # Initializing the result register
li $t2, 0 # Initializing the addition/counter register
main:
loop:
add $t2, $t2, 2 # Increase the value to be added by 2 (next even value)
bge $t2, $t0, fin # Check if the increment is larger than or equal to the initial input, if so break to finish
add $t1, $t1, $t2 # Increment the result by adding the even value
j loop # jump bak to the top of the loop
fin:
li $v0,1 # let the system know an integer is going to be printed
move $a0, $t1 # Load the result into the $a0 register (the register that prints values)
syscall # System Call
li $v0, 10 # Let the system know the program is going to exit
syscall # System Call
So as you can see $t2 increments by 2 each time. After each increment it is compared to the input value. If the input ($t0) than $t2 then add the value of $t2 to the result ($t1). This way there is an increment counter which is also used to add the necessary even value to the result.
Edit:
Not sure if this is entirely what you meant but I just tossed in some loads and saves, using the s registers as those are the register that are supposed to be used when saving values.
.data
N: .word 0
Result: .word 0
.text
.globl main
initialize:
li $v0, 5 # Getting arg1 from user
syscall # System Call
la $s0, N # Load the address of N into $s0
sw $v0, 0($s0) # Store the input value in 0 index of N
li $t2, 0 # Initializing the addition/counter register
la $s1, Result # Load the address of Result into $s1
main:
sw $t2, 0($s1) # Setting the 0 index of Result to 0
loop:
add $t2, $t2, 2 # Increase the value to be added by 2 (next even value)
lw $t4, 0($s0) # Loading the input value into the $t4 register
bge $t2, $t4, fin # Check if the increment is larger than or equal to the initial input, if so break to finish
lw $t4, 0($s1) # Loading the current result into the $t4 register
add $t4, $t4, $t2 # Increment the result by adding the even value
sw $t4, 0($s1) # Saving the new current result into the $t4 register
j loop # jump bak to the top of the loop
fin:
li $v0,1 # let the system know an integer is going to be printed
lw $a0, 0($s1) # Load the result into the $a0 register (the register that prints values)
syscall # System Call
li $v0, 10 # Let the system know the program is going to exit
syscall # System Call

How to count the number of words and print the result in mips?

So I am fairly new to mips and am trying to do a hmwk.
The exercise is to create a block of words with 0 as the last word , to count them knowing we don't consider the last element 0 and print out the result.
Here is my code for the moment
.data
blockOfWords: .word 12,43,549,7,60,0
.text
la $a0, blockOfWords #putting address of blockOfWords in $a0
loopStart: sll $t1, $s3,2 #iterates thru blockOfWords by jumping by 4 bytes, $t1=4*i
add $t1,$t1,$a0 #we increment the address by four so as to advance in the array after every iteration
lw $a1, 0($t1) #$a1=blockOfWOrds[i]
beq $a1,$zero, Exit #if the value in $a1[i]==0, exit the loop
addi $s0,$s0,1 #else, increment by one the cnt=$s0
j loopStart #and continue looping thru blockOfWords
Exit:
#how do i print the result?
So instead of doing a shift left logical it is a lot easier to up the memory address in the array
In this way the lw $a1, 0($a0) is just grabbing the beginning of the word
it is then incremented by 4 after a check for the 0. This makes the function much simpler and easier to read.
.data
blockOfWords: .word 12,43,549,7,60,0
.text
main:
la $a0, blockOfWords # Load beginning address into $a0
loopStart:
lw $a1, 0($a0) # load the value at the beginning of $a0 into $a1
beq $a1,$zero, exit # Check if $a1 is 0, if so jump to exit
addi $s0,$s0,1 # Add one to the count
addi $a0, $a0, 4 # Up the intial index of the array by 4, up one word
j loopStart # Re-loop
exit:
li $v0, 1 # Load the value of 1 into the $v0 register
la $a0, ($s0) # Load the counter into the $a0 address
syscall
li $v0, 10 # A value 10 syscall to indicate end of program
syscall

MIPS practice in writing lists of number

As the question required below,
Write a program in MIPS32 assembly language which reads a positive integer N and prints out the following:
1
12
123
1234
12345
...
1 2 3 4 5 6 ... N
Here is my code shown below:
.data
word: .asciiz "Please enter a random row: \n"
.text
.globl main
main:
la $a0, word # load word
li $v0, 4
syscall
li $v0, 1 # service 1 is print integer
move $a0, $t0 # move register to be printed into argument
register $a0
syscall
lw $s0, row # $s0 = row
addi $s0, $s0, -1 # for accommodating loop condition
li $s1, 1 # set i = 1
li $s2, 1 # set j = 1
loop1:
blt $s0, $s1, Exit # for(i = 0; i < row; i++)
addi $s1, $s1, 1 # i++
li $s2, 1 # resets j to 1 after every iteration of for
loop
move $a0, $t0 # move register to be printed into argument
register $a0
j loop2 # executing the nested for loop
loop2:
blt $s1, $s2, loop1 # for(i = 0; i < j; i++)
li $v0, 1 # read_double => scanf("%d")
move $a0, $t0 # move register to be printed into argument $a0
syscall
j loop2
li $v0, 10 # loading exit code
syscall # execute exit
As I tend to run it through, then I still could not achieve the expected outcome.
Here's how you'll write the code to do this:
Ask user for N value, & save.
Create a loop that will continue until N iterations (see conditional branching)
For N iterations, save the value 1, 1+=1, ... N in the register.
Remember that each word is 4 bytes. Make sure you are changing where you are accessing your register to save your values correctly, or else they will overwrite each other.
Use another loop to print all values (again, conditional branching).
If you want help with code, try writing some first. :-)

creating a check for a loop in driver

I created code for a procedure that outputs the factoral of a number given. But it needs to ask the user for a number until they enter a negative before it exits.
So that it looks something like this
Enter a value for n (or a negative value to exit): 6
6! is 720
Enter a value for n (or a negative value to exit): 9
9! is 362880
Enter a value for n (or a negative value to exit): 11
11! is 39916800
Enter a value for n (or a negative value to exit): 20
20! is -2102132736
Enter a value for n (or a negative value to exit): 100
100! is 0
Enter a value for n (or a negative value to exit): -1
Thanks for Testing!
Instead of something like this.
Enter the value of a number (or negative to exit): 5
Value returned is 120
Thanks for testing!
fact:
slti $t0, $a0, 1 # test for n < 1
beq $t0, $zero, L1 # if n >= 1, go to L1
li $v0, 1 # return 1
jr $ra # return to instruction after jal
L1:
addi $sp, $sp, -8 # adjust stack for 2 items
sw $ra, 4($sp) # save the return address
sw $a0, 0($sp) # save the argument n
addi $a0, $a0, -1 # n >= 1; argument gets (n – 1)
jal fact # call fact with (n – 1)
lw $a0, 0($sp) # return from jal: restore argument n
lw $ra, 4($sp) # restore the return address
addi $sp, $sp, 8 # adjust stack pointer to pop 2 items
mul $v0, $a0, $v0 # return n * fact (n – 1)
jr $ra # return to the caller
main:
la $a0, nreq # get value of n
li $v0, 4
syscall
li $v0, 5 # read value of n
syscall
move $a0, $v0 # place value n in $a0
jal fact # invoke fact
move $s0, $v0 #save value returned by facts
la $a0, ans # display
li $v0, 4
syscall
move $a0, $s0
li $v0, 1
syscall
la $a0, cr #display closing
li $v0, 4
syscall
li $v0, 10 # exit
syscall
.data
nreq: .asciiz "Enter a value for n (or negative to exit): "
ans: .asciiz "Value returned is "
cr: .asciiz "\nThanks for testing!\n"
Overall, pretty close. However, one or two things.
I'd move main to the top, above fact, as some simulators start at the lowest .text address rather than the given symbol main. For example, in mars, this didn't seem to work until I reversed the order.
main was missing the test for negative input and didn't loop on itself.
Here's a version that seems to work [please pardon the gratuitous style cleanup]:
.text
.globl main
main:
la $a0,nreq # get value of n
li $v0,4
syscall
li $v0,5 # read value of n
syscall
# NOTE/BUG: add this
bltz $v0,exit # exit program on negative
move $a0,$v0 # place value n in $a0
jal fact # invoke fact
move $s0,$v0 # save value returned by facts
la $a0,ans # display
li $v0,4
syscall
move $a0,$s0
li $v0,1
syscall
# NOTE: add this
li $v0,4
la $a0,nl
syscall
j main
exit:
la $a0,cr # display closing
li $v0,4
syscall
li $v0,10 # exit
syscall
fact:
slti $t0,$a0,1 # test for n < 1
beq $t0,$zero,L1 # if n >= 1, go to L1
li $v0,1 # return 1
jr $ra # return to instruction after jal
L1:
addi $sp,$sp,-8 # adjust stack for 2 items
sw $ra,4($sp) # save the return address
sw $a0,0($sp) # save the argument n
addi $a0,$a0,-1 # n >= 1; argument gets (n – 1)
jal fact # call fact with (n – 1)
lw $a0,0($sp) # return from jal: restore argument n
lw $ra,4($sp) # restore the return address
addi $sp,$sp,8 # adjust stack pointer to pop 2 items
mul $v0,$a0,$v0 # return n * fact (n – 1)
jr $ra # return to the caller
.data
nreq: .asciiz "Enter a value for n (or negative to exit): "
ans: .asciiz "Value returned is "
nl: .asciiz "\n"
cr: .asciiz "\nThanks for testing!\n"

MIPS Mult two numbers and result it negative number

I am new for MIPS, there is my code:
.text
main:
add $s0, $zero, 1 # set $s0 to 0 for the initial value for the following loop
Loop: jal srand # Call function srand
addi $s0, $s0, 1 # $s0 = i++
slti $s1, $s0, 6 # $s1 < 6
bne $s1, $zero, Loop # go to loop in i < 6
beq $s1, 6, end_loop # go out the loop when i == 6
end_loop:
li $v0, 10
syscall
srand: # This function will set the numbers for future calculation
lw $t0, a # Load a value to $t0 1103515245
lw $t1, c # Load c value to $t1 12345
lw $t2, m # Load m value to $t2 2147483648
multu $t0,$s0 # result for multiplication (Xn*a) and store the result to $t3
add $t4, $t3, $t1 # result for add multiplication (Xn*a+c) and store the result to $t4
move $a0, $t4 # Debug function
li $v0, 1 # Debug function
syscall # Debug function
la $a0, msg
li $v0, 4
syscall
jr $ra
There is a problem, when the code goes to this "multu $t0,$s0" commend and result will be wrong.
1103515245 * 2 returned a negative number -2087936806
anyone know how to fix it ??
thanks
As chrylis said, it looks like integer overflow. If that's unclear to you, you should read up on two's complement integer representations.
Basically, the value of the highest-order bit is defined to be negative. Suppose you have 32-bit integers. Then 0x800000 will have the value of -2**32, and the other bits have their normal value, so you end up with an expression that looks like -2**32 + [the sum of the other bits], in particular 0xFFFFFFFF has the value of -1, 0xFFFFFE is -2, and so on.