2012-11-20 129 views
3

我試圖找出下面我的代碼究竟出了什麼問題。MIPS浮點錯誤

快速背景:該計劃的想法是根據球員進行的單打,雙打,三分球,Homeruns和Outs的數量來計算擊球平均和扣球百分比。其中一個針對代碼運行的測試用例具有這些天文數據的價值,並且每當我嘗試任何添加時,代碼都會失敗。我意識到我需要使用雙精度浮點數(特別是在添加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 

回答

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