3

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

快速背景:这个程序的想法是根据球员的单打、双打、三打、本垒打和出局的数量来计算平均击球率和击球率。我针对代码运行的一个测试用例的值是天文数字,每当我尝试对它们进行任何形式的加法时,代码都会失败。我意识到我需要使用双点浮点数(特别是在添加 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
4

1 回答 1

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
于 2012-11-20T15:19:34.097 回答