3

以下のコードで何が問題なのかを正確に把握しようとしています。

簡単な背景: このプログラムのアイデアは、プレーヤーが実行したシングルス、ダブルス、トリプルス、ホームラン、およびアウトの量に基づいて打率と長打率を計算することです。私がコードに対して実行しているテスト ケースの 1 つは、これらの値が天文学的であることを示しており、それらに何らかの追加を試みるたびに、コードは失敗します。double-point float を使用する必要があることは認識していますが (特に Out と Hit を追加する場合、最終的には 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 に答える