MIPS浮点错误

时间:2012-11-20 06:25:12

标签: floating-point mips

我正试图弄清楚下面的代码到底出了什么问题。

快速背景:此计划的想法是根据玩家执行的单打,双打,三重,本垒打和外出的数量来计算击球平均值和扣球百分比。我针对代码运行的一个测试用例的值是天文数字,每当我尝试添加它们时,代码都会失败。我意识到我需要使用双点浮点数(特别是在添加Outs和Hits时,最终应该使用数字31,500,032而不是存储26,207,920),但我不确定如何使用我的代码来处理这样做。有什么建议吗?

# 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

1 个答案:

答案 0 :(得分:2)

你的问题是你正在混合整数和浮点算术。 您的输入数字表示为整数。 然后将它们放入浮点寄存器并与它们一起操作。但是,您没有将它们转换为浮点表示。

对于小数字,加法和除法工作正常(你只添加或划分尾数)。但是,当任何算术运算中涉及的数字的指数不同时,操作将产生错误的结果。

在执行浮点运算之前,您应该做的是将数字的整数表示转换为浮点表示。 在MIPS中,这是通过cvt.s.w指令完成的。

所以基本上,您必须在每个mtc1发布之后添加其中一个转换:

     # 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