Github項目地址: https://github.com/JtvDeemo/elementary arithmetic PSP ||||| |: |: |: |: | | PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘 ...
Github項目地址:
https://github.com/JtvDeemo/elementary-arithmetic
PSP
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
Planning | 計劃 | 10 | 10 |
· Estimate | · 估計這個任務需要多少時間 | 1440 | 920 |
Development | 開發 | 700 | 200 |
· Analysis | · 需求分析 (包括學習新技術) | 180 | 240 |
· Design Spec | · 生成設計文檔 | 5 | 5 |
· Design Review | · 設計覆審 (和同事審核設計文檔) | 10 | 15 |
· Coding Standard | · 代碼規範 (為目前的開發制定合適的規範) | 5 | 5 |
· Design | · 具體設計 | 40 | 60 |
· Coding | · 具體編碼 | 300 | 380 |
· Code Review | · 代碼覆審 | 30 | 30 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 30 | 30 |
Reporting | 報告 | 120 | 120 |
· Test Report | · 測試報告+博客 | 120 | 120 |
· Size Measurement | · 計算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事後總結, 並提出過程改進計劃 | 40 | 50 |
合計 | 3040 | 2195 |
題目要求:
- 能自動生成小學四則運算題目
- 除了整數外,還要支持真分數的四則運算
除了以上的基本需求,還有 - 生成的算式長度隨機
- 能處理分數的運算,結果能用分數(字元串類型)表示出來,能與用戶輸入相對應
解題思路:
- 定義一個函數用於隨機生成隨機長度的算式
- 把字元串型的算式轉換為逆波蘭式(RPN,也稱尾碼表達式)
- 再把尾碼表達式利用棧結構計算出結果
- 最後再與用戶的輸入做比較
重點難點:
- 分數的表示與計算
- 尾碼表達式的生成和計算
- 結果為負數的情況
如何解決:
- Python的分數計算可以用 fractions 庫
- https://blog.csdn.net/qq_36763635/article/details/72627601 這裡介紹瞭如何將中綴表達式轉換為尾碼表達式(RPN)
- https://blog.csdn.net/yangquanhui1991/article/details/52187375 圖解尾碼表達式的計算過程
- 對於結果為負數的情況,只能生成算式之後驗算一遍,若為負數的情況,重新生成一遍(可能是個人水平有限)
設計實現:
具體程式設計:
成員變數
成員名 | 類型 | 功能 |
op | list | 存放運算符 |
quest | str | 存放算式 |
lens | int | 2到9的隨機長度 |
teop | str | 存放當前運算符 |
tstr | str | 存放當前算式 |
tint | int | 存放當前運算數 |
成員函數
函數名 | 輸入 | 輸出 | 依賴函數 | 功能 |
get_string | 冇 | 字元串 | 冇 | 隨機生成一個算式 |
get_ans | str | 返回布爾類型 | get_string | 將用戶輸入與正確答案比較 |
to_rpn | str | 返回尾碼表達式 | get_ans | 將隨機生成的算式轉換為RPN |
this_bigger | str,str | 返回布爾表達式 | 冇啊 | 比較兩個運算符的優先順序 |
slove_rpn | str | 返回計算結果 | get_ans | 將尾碼表達式計算出來 |
核心代碼:
#隨機生成一個算式
def get_string(self):
self.lens = random.randint(2, 9)
self.teop = ''
self.tstr = []
for i in range(self.lens):
if self.teop == '÷':
self.tint = random.randint(1, 8)
self.teop = random.choice(self.op)
elif self.teop == '/':
self.tint = random.randint(self.tint+1, 9)
self.teop = random.choice(self.op[:-1])
else:
self.tint = random.randint(0, 8)
self.teop = random.choice(self.op)
self.tstr.append(str(self.tint))
self.tstr.append(self.teop)
self.tstr[-1] = '='
self.tstr = ''.join(self.tstr)
self.quest = self.tstr
return self.tstr
#將隨機生成的算式轉換為RPN
def to_rpn(self, ques): #Reverse Polish notation
self.stack = []
s = ''
for x in ques:
if x != '+' and x != '-' and x != '×' and x != '÷' and x != '/':
s += x #若為數字,直接輸出
else: # 若為運算符,進棧
if not self.stack: #棧空
self.stack.append(x)
else:
if self.this_bigger(x, self.stack[-1]): #運算級高於棧頂元素
self.stack.append(x) #直接進棧
else:
while self.stack:
if self.this_bigger(x, self.stack[-1]):
break
s += self.stack.pop()
self.stack.append(x)
while self.stack:
s += self.stack.pop()
# print('在to_rpn函數中,rpn:',s)
return s
#將尾碼表達式計算出來
def slove_rpn(self, rpn):
#print('進入slove_rpn函數:')
self.stack1 = [] #用於保存運算數
for x in rpn:
if x != '+' and x != '-' and x != '×' and x != '÷' and x != '/':
self.stack1.append(int(x))
elif x == '+':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(first + second)
elif x == '-':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(first - second)
elif x == '×':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(first * second)
elif x == '÷':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(Fraction(first, second))
elif x == '/':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(Fraction(first, second))
resault = self.stack1[0]
if resault >= 0:
#print('--------------題結束----------------')
return resault
elif resault < 0:
s = self.get_string()
rpn = self.to_rpn(s[:-1])
return self.slove_rpn(rpn)
運行效果:
單元測試
《構建之法》第二章中詳細提及了好的單元測試的標準。
- 單元測試應該在最基本的功能/參數上檢驗程式的正確性。
- 單元測試必須由最熟悉代碼的人來寫。
- 單元測試過後,機器狀態保持不變。
- 單元測試要快。
- 單元測試應該產生可重覆、一致的結果。
- 獨立性-單元測試的運行/通過/失敗不依賴於別的測試,可以人為構造數據,以保持測試的獨立性。
- 單元測試應該覆蓋所有代碼路徑。
效能分析圖
Pycharm中運行profiler,次數為10W次
可以看到所用的時間長度為16.04s