咳咳,該課上測試了xdm,P2 課下通過了沒!C 語言代碼翻譯熟悉了沒~
如果你很順利通過所有題目 + 附加題,那麼 dalao 就是你嘞!
經過了上篇中提到的 P2 課下作業以及附加題那些練習之後,是時候在上機測試中展現自己的能力了。
到了第三次課上的測試環節,我們會遇到一些新挑戰,時間比 P1 緊,要寫的代碼量較大,不過這些應該還是難不倒大家的(作者 P2 掛了)。
我們展示了 2020 秋的 P2 第 1、2 次上機題作為參考,如果你想把這些作為一次全真測試,那麼請先做完之後再看示例。另外,由於 P0 上機測試題僅有第 1、2 次的,所以考試難度不一定和這些題目相同,僅供參考~
go!
由於本次上機為彙編程序寫作,所有題目有很多共性,所以就不再根據個別題目具體分析。
步驟一般分為:題意分析、C 代碼編寫、高效彙編語言翻譯、Debug 或 冗餘翻譯縮減。
題意分析:直接看清楚題意,看清楚題目的限制,注意各變量範圍。注意如果題目中有 unsigned 的類型,對應指令跟著改變。
C 代碼編寫:這一步就是使用 C 語言實現題意,儘量可以在這一層把 循環、判斷 等進行標記,這樣在翻譯成彙編代碼的時候可以更好發現問題。
高效彙編語言翻譯:這一步要儘量避免冗餘步數,例如:乘除 2 的倍數時候直接使用移位指令,而不需要使用 mult、div、mflo 、mfhi等指令。另外,每一個程序段要做一些標記,Debug 時候也會變得簡單一些。
Debug:這布需要用到 Mars 上面的斷點標記,之後可以選擇單步執行,或循環內部也可以直接繼續運行,相當於 Dev 中的 跳過。另外,不要忘記關閉延遲槽,不關閉很有可能導致運行錯誤,如果你不知道我在說什麼,不要動 Mars 就好啦~(Settings -> Delayed branching 要關閉)
冗餘翻譯縮減:有時候會遇到步數限制導致 TLE,這個時候可以進行冗餘翻譯縮減,即改變指令條數獲得同樣效果,不過一般不會出現這種情況,出現了現場如果沒有大幅優化的地方也比較難辦。
*特別注意:
1. 寫 for 或 loop 的時候,不要忘記先判斷一下是否符合循環條件,而不要循環運行完第 1 次之後再判斷。
2. 寫程序的時候如果你本地運行正常,而且查不出來 bug,而放到評測機上會出現 Runtime Error,這種情況不要慌,用記事本打開你的 asm 文件,看看有沒有異常字符。(作者第一次掛掉了 P2,因為在敲入 "li $v0, 4" 指令的時候,不知道為何敲入了圓角的數字 4,在 Mars 上看不出來圓半角 4 的區別,但本地一直可以運行。評測機所有的樣例返回均是 Runtime Error,問助教哥哥也解答不出來,浪費了很長時間使用 ANSI 編碼打開發現,4 根本就顯示不出來,嗚嗚)
任務
具體要求
請使用 syscall 結束程序:
li $v0, 10
syscall
MIPS彙編實現(Author:cja) .data .text li $v0, 5 syscall move $s0, $v0 blt $s0, 2, load0 beq $s0, 2, load1 li $t0, 2 for: mul $t1, $t0, $t0 bgt $t1, $s0, load1 div $s0, $t0 mfhi $t2 beqz $t2, load0 add $t0, $t0, 1 j for load1: li $a0, 1 j print load0: li $a0, 0 print: li $v0, 1 syscall
約瑟夫環(P2s1.Q2)任務
具體要求
MIPS彙編實現1(Author:lxl) .data matrix: .space 404 str_enter: .asciiz "\n" .macro get(%ans, %i, %addr) move %ans, %i sll %ans, %ans, 2 la %ans, %addr(%ans) .end_macro .eqv n, $s0 .eqv x, $s1 .eqv data, $s2 .eqv i, $t0 .eqv temp, $t1 .eqv num, $t2 .eqv address, $t3 .eqv one, $t9 .text li one, 1 li $v0, 5 syscall move n, $v0 li $v0, 5 syscall move x, $v0 cycle1: li temp, 0 cycle2: beq temp, x, out2 div i, n mfhi i addi i, i, 1 get(address, i, matrix) lw data, (address) bnez data, return addi, temp, temp,1 return: ble temp, x, cycle2 out2: move $a0, i li $v0, 1 syscall la $a0, str_enter li $v0, 4 syscall get(address, i, matrix) sw one, (address) addi num, num, 1 blt num, n, cycle1 out1: li $v0, 10 syscall
MIPS彙編實現2(Author:cja) .data nxt: .space 400 pre: .space 400 endl: .asciiz "\n" .text li $v0, 5 syscall move $s0, $v0 li $v0, 5 syscall move $s1, $v0 li $t0, 0 For: bge $t0, $s0, Pre add $t1, $t0, 1 sub $t2, $t0, 1 sll $t3, $t0, 2 sw $t1, nxt($t3) sw $t2, pre($t3) add $t0, $t0, 1 j For Pre: sub $t0, $s0, 1 sll $t3, $t0, 2 sw $0, nxt($t3) sw $t0, pre($0) li $t1, 0 while: beqz $s0, return sub $s0, $s0, 1 li $t0, 1 for: bge $t0, $s1, for_end sll $t3, $t1, 2 lw $t2, nxt($t3) move $t1, $t2 add $t0, $t0, 1 j for for_end: sll $t4, $t1, 2 lw $t2, pre($t4) lw $t3, nxt($t4) sll $t4, $t2, 2 sw $t3, nxt($t4) sll $t4, $t1, 2 lw $t2, pre($t4) lw $t3, nxt($t4) sll $t4, $t3, 2 sw $t2, pre($t4) add $a0, $t1, 1 li $v0, 1 syscall la $a0, endl li $v0, 4 syscall move $t1, $t3 j while return: li $v0, 10 syscall
快速排序(P2s1.Q3)任務
具體要求
MIPS彙編實現(Author:cja) .data array: .space 4000 endl: .asciiz "\n" .text main: li $v0, 5 syscall move $s0, $v0 li $t0, 0 for: bge $t0, $s0, print li $v0, 5 syscall sll $t1, $t0, 2 sw $v0, array($t1) add $t0, $t0, 1 j for print: add $a0, $0, 0 sub $a1, $s0, 1 jal qsort li $t0, 0 For: bge $t0, $s0, exit sll $t1, $t0, 2 lw $a0, array($t1) li $v0, 1 syscall la $a0, endl li $v0, 4 syscall add $t0, $t0, 1 j For exit: li $v0, 10 syscall qsort: bge $a0, $a1, return sub $sp, $sp, 4 sw $ra, ($sp) jal get lw $ra, ($sp) add $sp, $sp, 4 sub $sp, $sp, 16 sw $ra, ($sp) sw $a0, 4($sp) sw $a1, 8($sp) sw $v0, 12($sp) sub $a1, $v0, 1 jal qsort lw $ra, ($sp) lw $a0, 4($sp) lw $a1, 8($sp) lw $v0, 12($sp) add $sp, $sp, 16 sub $sp, $sp, 16 sw $ra, ($sp) sw $a0, 4($sp) sw $a1, 8($sp) sw $v0, 12($sp) add $a0, $v0, 1 jal qsort lw $ra, ($sp) lw $a0, 4($sp) lw $a1, 8($sp) lw $v0, 12($sp) add $sp, $sp, 16 return: jr $ra get: move $t0, $a0 move $t1, $a1 sll $t2, $t0, 2 lw $s1, array($t2) while: bge $t0, $t1, while_end loop1: bge $t0, $t1, if1 sll $t2, $t1, 2 lw $t3, array($t2) blt $t3, $s1, if1 sub $t1, $t1, 1 j loop1 if1: bge $t0, $t1, loop2 sll $t2, $t1, 2 lw $t3, array($t2) sll $t2, $t0, 2 sw $t3, array($t2) loop2: bge $t0, $t1, if2 sll $t2, $t0, 2 lw $t3, array($t2) bgt $t3, $s1, if2 add $t0, $t0, 1 j loop2 if2: bge $t0, $t1, while_end sll $t2, $t0, 2 lw $t3, array($t2) sll $t2, $t1, 2 sw $t3, array($t2) j while while_end: sll $t2, $t0, 2 sw $s1, array($t2) move $v0, $t0 jr $ra
附加題(P2s1.Qs)計小組在做回文串判斷的時候遇到了一些問題,在此想求助一下大家。
下面是簡要的 回文串判斷 題目:
判斷輸入的字符串是不是回文串,如果是回文串則輸出 right,否則輸出 wrong。
下面是計小組的代碼:
當計小組輸入 5 以及 abcca 的時候,程序正確輸出了 wrong,當他滿心歡喜的提交評測時,卻是 WA 聲一片,請大家來幫幫計小組。
上面的代碼中有多處問題,請在下面的選項中選出這段代碼的錯誤:
A. data段的預定義錯誤
B. read部分錯誤
C. judge部分錯誤
D. print(包括print_right和print_wrong)部分錯誤
(和上次一樣,答案在最後,建議做完了以後對答案)
水仙花數(P2s2.Q1)任務
具體要求
第一行讀取m,第二行讀取n
計算並從小到大順序輸出[m, n)範圍內所有的水仙花數
保證m<n,且m>=100,n<=999
水仙花數定義:判斷一個數是否為「水仙花數」,最重要的是要把給出的三位數的個位、十位、百位分別拆分,並求其立方和(設為s),若s與給出的三位數相等, 三位數為「水仙花數」,反之,則不是。
步數限制為200,000
請使用syscall結束程序:
li $v0, 10
syscall
MIPS彙編實現(Author:cja) .data endl: .asciiz "\n" .macro cube(%ans) mul $t5, %ans, %ans mul %ans, %ans, $t5 .end_macro .text main: li $v0, 5 syscall move $s0, $v0 li $v0, 5 syscall move $s1, $v0 li $s2, 10 li $s3, 100 move $t0, $s0 for: bge $t0, $s1, return div $t0, $s2 mfhi $t1 mflo $t4 cube($t1) div $t4, $s2 mfhi $t2 cube($t2) div $t0, $s3 mflo $t3 cube($t3) add $a0, $t1, $t2 add $a0, $a0, $t3 bne $a0, $t0, for_end li $v0, 1 syscall la $a0, endl li $v0, 4 syscall for_end: add $t0, $t0, 1 j for return: li $v0, 10 syscall*注意:(這段不用看,忘記刪了)subi %index, %index, 1 這句話剛開始我是沒有的,最後導致存儲位置都被覆蓋掉了。Debug 看了一會才知道,遞歸完成回來以後,這個 index 要減 1,或者你就在內部進行變化,不要在函數出入口做一些很複雜、不必要的變量加減(不適用於所有情況)。
二分查找(P2s2.Q2)任務
具體要求
第一行為一個數字m,為需要查找的數組大小,m<1000
接下來m行,每一行一個數字,代表數組對應的元素,整個數組中的元素不重複且從小到大排列
接下來一行為一個數字n,為需要查找存在性的數字個數
接下來n行,每一行為一個數字,查詢這個是否存在,存在則輸出1,不存在則輸出零
二分查找C語言算法提示:
int binary_search(int key,int a[],int n) { int low,high,mid,count=0,count1=0; low=0; high=n-1; while(low<=high) { count++; mid=(low+high)/2; if(key<a[mid]) high=mid-1; else if(key>a[mid]) low=mid+1; else if(key==a[mid]) { printf("1"); count1++; break; } } if(count1==0) printf("0"); return 0; }步數限制為200,000
請使用syscall結束程序:
li $v0, 10
syscall
MIPS彙編實現(Author:cja) .data a: .space 4000 endl: .asciiz "\n" .text li $v0, 5 syscall move $s0, $v0 li $t0, 0 for: bge $t0, $s0, for_end li $v0, 5 syscall sll $t1, $t0, 2 sw $v0, a($t1) add $t0, $t0, 1 j for for_end: li $v0, 5 syscall move $s1, $v0 li $t5, 0 For: bge $t5, $s1, For_end li $v0, 5 syscall move $s2, $v0 jal bsearch add $t5, $t5, 1 j For For_end: li $v0, 10 syscall bsearch: li $t0, 0 sub $t1, $s0, 1 while: bgt $t0, $t1, while_end add $t2, $t0, $t1 srl $t2, $t2, 1 sll $t3, $t2, 2 lw $t4, a($t3) blt $s2, $t4, if bgt $s2, $t4, else beq $s2, $t4, equal if: sub $t1, $t2, 1 j while else: add $t0, $t2, 1 j while equal: li $a0, 1 li $v0, 1 syscall la $a0, endl li $v0, 4 syscall jr $ra while_end: li $a0, 0 li $v0, 1 syscall la $a0, endl li $v0, 4 syscall jr $ra
約瑟夫(P2s2.Q3)同(P2s1.Q2) 。
其實如果你多考幾次 P2 就知道,P2 前一次的第 3 題會被挪到第 2 題,不過不是一般規律。
好啦,以上就是 重製版的第 6 期【我的計組生活】
希望能有幫助到你哦!!來一波贊和在看可好?甚至是不是還可以來一波打賞~哈哈哈!
如果看到有錯誤還請一定聯繫作者更改,可以在後臺直接進行留言~,拜託各位大佬們了!
謝謝大家,下一期我們正式開始接觸搭建 CPU,那麼我們 P3 課下見~
附加題不定項選擇答案:BCE。