Reputation: 33
I'm attempting to figure out what exactly is going wrong with my code below.
Quick background: The idea of this program is to calculate the Batting Average and Slugging Percentage based upon the amount of Singles, Doubles, Triples, Homeruns and Outs performed by a player. One of the test cases I am running against the code has the values for these being astronomical, and whenever I attempt any sort of addition with them, the code fails. I realize that I need to use double-point floats (particularly when adding Outs and Hits, which should end up with the number 31,500,032 but instead stores 26,207,920), but I'm not at all sure how to go about working with my code to do so. Any suggestions?
# test with three batters, both average and slugging percentage
# First batter has no hits, but does have outs
# Second batter has hits and outs, with realistic values
# Third hitter has large values for some of the hits and for the
# outs. This means the hits and outs *have* to be converted from int's
# to float's in order to get the right answer.
.data
mainNumBatters:
.word 3
mainBatter1:
.word 0, 0, 0, 15, 0 # player with no atBats
mainBatter2:
.word 101 # singles
.word 22 # doubles
.word 4 # triples
.word 423 # outs
.word 10 # home runs
mainBatter3:
.word 8000000 # singles
.word 22 # doubles
.word 500000 # triples
.word 23000000 # outs
.word 10 # home runs
mainNewline:
.asciiz "\n"
mainBatterNumber:
.asciiz "Batter number: "
mainBattingAverage:
.asciiz "Batting average: "
mainSluggingPercentage:
.asciiz "Slugging percentage: "
.text
main:
# Function prologue -- even main has one
subu $sp, $sp, 24 # allocate stack space -- default of 24 here
sw $fp, 0($sp) # save frame pointer of caller
sw $ra, 4($sp) # save return address
addiu $fp, $sp, 20 # setup frame pointer of main
# for (i = 0; i < mainNumBatters; i++)
# compute batting average
# compute slugging average
la $s0, mainNumBatters
lw $s7, 0($s0) # $s7 = number of batters
addi $s6, $zero, 0 # $s6 = i = 0
la $s0, mainBatter1 # $s0 = addr of current batter's stats
mainLoopBegin:
slt $t0, $s6, $s7 # $t0 = i < number of batters
beq $t0, $zero, mainDone
la $a0, mainBatterNumber
addi $v0, $zero, 4
syscall
addi $a0, $s6, 1
addi $v0, $zero, 1
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
lw $a1, 0($s0) # $a1 = singles
lw $a2, 4($s0) # $a2 = doubles
lw $a3, 8($s0) # $a3 = triples
lw $s5, 16($s0) # $s5 = home runs
lw $s4, 12($s0) # $s4 = outs
sw $s4, -4($sp) # put outs at top of average's stack
sw $s5, -8($sp) # put homeruns 2nd fm top of average's stack
addi $a0, $zero, 1 # $a0 = 1 = compute batting average
jal average
# Print the average
mtc1 $v0, $f12 # get result fm $v0 before we print string
la $a0, mainBattingAverage
addi $v0, $zero, 4
syscall
addi $v0, $zero, 2 # print the average
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
syscall
# do it again for the slugging percentage
lw $a1, 0($s0) # $a1 = singles
lw $a2, 4($s0) # $a2 = doubles
lw $a3, 8($s0) # $a3 = triples
lw $s5, 16($s0) # $s5 = home runs
lw $s4, 12($s0) # $s4 = outs
sw $s4, -4($sp) # put outs at top of average's stack
sw $s5, -8($sp) # put homeruns 2nd fm top of average's stack
addi $a0, $zero, 2 # $a0 = 1 = compute batting average
jal average
# Print the slugging percentage
mtc1 $v0, $f12 # get result fm $v0 before we print string
la $a0, mainSluggingPercentage
addi $v0, $zero, 4
syscall
addi $v0, $zero, 2 # print the average
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
syscall
addi $s6, $s6, 1 # i++
addi $s0, $s0, 20 # $s0 = addr of next batter's stats
j mainLoopBegin
mainDone:
# Epilogue for main -- restore stack & frame pointers and return
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore frame pointer for caller
addiu $sp, $sp, 24 # restore frame pointer for caller
jr $ra # return to caller
.data
printHitsOuts:
.asciiz "Outs: "
printHitsSingles:
.asciiz "Singles: "
printHitsDoubles:
.asciiz "Doubles: "
printHitsTriples:
.asciiz "Triples: "
printHitsHomeruns:
.asciiz "Homeruns: "
printHitsNewline:
.asciiz "\n"
.text
printHits:
# Function prologue
addiu $sp, $sp, -28 # allocate stack space
sw $fp, 0($sp) # save frame pointer of caller
sw $ra, 4($sp) # save return address
sw $a0, 8($sp) # save $a0 thru $a3
sw $a1, 12($sp)
sw $a2, 16($sp)
sw $a3, 20($sp)
addiu $fp, $sp, 24 # setup frame pointer of average
# print the outs
la $a0, printHitsOuts
addi $v0, $zero, 4
syscall
lw $a0, 24($sp) # the outs are at the top of our stack
addi $v0, $zero, 1
syscall
la $a0, printHitsNewline
addi $v0, $zero, 4
syscall
# print the singles
la $a0, printHitsSingles
addi $v0, $zero, 4
syscall
lw $a0, 8($sp)
addi $v0, $zero, 1
syscall
la $a0, printHitsNewline
addi $v0, $zero, 4
syscall
# print the doubles
la $a0, printHitsDoubles
addi $v0, $zero, 4
syscall
addi $a0, $a1, 0
addi $v0, $zero, 1
syscall
la $a0, printHitsNewline
addi $v0, $zero, 4
syscall
# print the triples
la $a0, printHitsTriples
addi $v0, $zero, 4
syscall
addi $a0, $a2, 0
addi $v0, $zero, 1
syscall
la $a0, printHitsNewline
addi $v0, $zero, 4
syscall
# print the homeruns
la $a0, printHitsHomeruns
addi $v0, $zero, 4
syscall
addi $a0, $a3, 0
addi $v0, $zero, 1
syscall
la $a0, printHitsNewline
addi $v0, $zero, 4
syscall
printHitsDone:
# Epilogue for average -- restore stack & frame pointers and return
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore frame pointer for caller
addiu $sp, $sp, 28 # restore frame pointer for caller
jr $ra # return to caller
# Your code goes below this line
# $s1 = Homeruns = $f6
# Outs = $f8
# atBats = $f10
# $a1 = Singles = $f12
# $a2 = Doubles = $f14
# $a3 = Triples = $f16
# $f20 = Slugging Percentage (Not Divided)
# $f18 = Hits
# $f2 = Batting Average
average:
# Function prologue
addiu $sp, $sp, -56 # allocate stack space
sw $fp, 0($sp) # save frame pointer of caller
sw $ra, 4($sp) # save return address
sw $a0, 8($sp) # 1 or 2 ; 1, batting average ; 2, slugging percentage
sw $a1, 12($sp) # Number of Singles
sw $a2, 16($sp) # Number of Doubles
sw $a3, 20($sp) # Number of Triples
addiu $fp, $sp, 24 # setup frame pointer of average
sw $s0, 28($sp)
sw $s1, 32($sp)
sw $s2, 36($sp)
sw $s3, 40($sp)
sw $s4, 44($sp)
# Grab Outs and Homeruns from Top of Main stack
lw $s0, 52($sp) # Number of Outs
lw $s1, 48($sp) # Number of Homeruns
# Convert Everything to Floating
mtc1 $s1, $f6 # $f6 = Homeruns
mtc1 $s0, $f8 # $f8 = Outs
mtc1 $a1, $f12 # $f12 = Singles
mtc1 $a2, $f14 # $f14 = Doubles
mtc1 $a3, $f16 # $f16 = Triples
# Calculate Hits ($f18)
add.s $f18, $f12, $f14 # Add Singles and Doubles
add.s $f18, $f18, $f16 # Add Triples
add.s $f18, $f18, $f6 # Add Homeruns
#Calculate atBats ($f10)
add.s $f10, $f8, $f18 # Add Outs and Hits
#Check if Batting or Slugging is to be computed
add $s4, $zero, $zero
addi $s4, $s4, 2
beq $s4, $a0, averageSlugging
averageBatting:
#Skip when atBats = 0
mfc1 $s3, $f10
beqz $s3, averageFinish
#Calculate Batting Average ($f4)
div.s $f4, $f18, $f10 # Divide Hits by atBats
j averageFinish
averageSlugging:
#Skip when atBats = 0
mfc1 $s3, $f10
beqz $s3, averageFinish
#Calculate Slugging Average ($f0)
add.s $f20, $f12, $f14 # $f20 = Singles + Doubles
add.s $f20, $f20, $f14 # $f20 = Singles + Doubles*2
add.s $f20, $f20, $f16 # $f20 = Singles + Doubles*2 + Triples
add.s $f20, $f20, $f16 # $f20 = Singles + Doubles*2 + Triples*2
add.s $f20, $f20, $f16 # $f20 = Singles + Doubles*2 + Triples*3
add.s $f20, $f20, $f6 # $f20 = Singles + Doubles*2 + Triples*3 + Homeruns
add.s $f20, $f20, $f6 # $f20 = Singles + Doubles*2 + Triples*3 + Homeruns*2
add.s $f20, $f20, $f6 # $f20 = Singles + Doubles*2 + Triples*3 + Homeruns*3
add.s $f20, $f20, $f6 # $f20 = Singles + Doubles*2 + Triples*3 + Homeruns*4
div.s $f4, $f20, $f10 # Divide Hits by atBats
averageFinish:
#Call printHits
add $a0, $a1, $zero # $a0 = Singles
add $a1, $a2, $zero # $a1 = Doubles
add $a2, $a3, $zero # $a2 = Triples
add $a3, $s1, $zero # $a3 = Homeruns
sw $s0, -4($sp) # Outs at the top of printHits Stack
jal printHits
#Prepare for Return
mfc1 $v0, $f4
mtc1 $zero, $f4 # $f4 = 0
# Epilogue for average -- restore stack & frame pointers and return
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore frame pointer for caller
lw $a0, 8($sp) # 1 or 2 ; 1, batting average ; 2, slugging percentage
lw $a1, 12($sp) # Number of Singles
lw $a2, 16($sp) # Number of Doubles
lw $a3, 20($sp) # Number of Triples
lw $s0, 28($sp)
lw $s1, 32($sp)
lw $s2, 36($sp)
lw $s3, 40($sp)
lw $s4, 44($sp)
addiu $sp, $sp, 56 # restore frame pointer for caller
jr $ra # return to caller
Upvotes: 3
Views: 1811
Reputation: 22585
Your problem is that you are mixing integer and floating point arithmetics. Your input numbers are represented as integers. Then you put them into floating point registers and operate with them. However you did not convert them to floating point representation.
For small numbers the addition and division works fine (you only add or divide the mantissas). However, when the numbers involved in any arithmetic operation differ in their exponent the operation will yield wrong results.
What you should do is convert the integer representation of your numbers to a floating point representation before performing floating point operations.
In MIPS this is done with the cvt.s.w
instruction.
So basically, you have to add one of this conversions after each mtc1
you have issued:
# Convert Everything to Floating
mtc1 $s1, $f6 # $f6 = Homeruns
cvt.s.w $f6, $f6 # (convert to floating point)
mtc1 $s0, $f8 # $f8 = Outs
cvt.s.w $f8, $f8
mtc1 $a1, $f12 # $f12 = Singles
cvt.s.w $f12, $f12
mtc1 $a2, $f14 # $f14 = Doubles
cvt.s.w $f14, $f14
mtc1 $a3, $f16 # $f16 = Triples
cvt.s.w $f16, $f16
Upvotes: 2