軟工第五次作業——Python效能分析之四則運算生成器

来源:https://www.cnblogs.com/GitHung-Zeng/archive/2018/04/19/8877981.html
-Advertisement-
Play Games

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,也稱尾碼表達式)
  • 再把尾碼表達式利用棧結構計算出結果
  • 最後再與用戶的輸入做比較

重點難點:

  1. 分數的表示與計算
  2. 尾碼表達式的生成和計算
  3. 結果為負數的情況

如何解決:

  1. Python的分數計算可以用 fractions 庫
  2. https://blog.csdn.net/qq_36763635/article/details/72627601 這裡介紹瞭如何將中綴表達式轉換為尾碼表達式(RPN)
  3. https://blog.csdn.net/yangquanhui1991/article/details/52187375 圖解尾碼表達式的計算過程
  4. 對於結果為負數的情況,只能生成算式之後驗算一遍,若為負數的情況,重新生成一遍(可能是個人水平有限)

設計實現:

具體程式設計:

成員變數

成員名 類型 功能
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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文地址:http://hadihariri.com/2014/06/24/no-tabs-in-intellij-idea/ I often come across people complaining about some odd behaviour when it comes to edito ...
  • @ResponseBody 在返回的數據不是html標簽的頁面,而是其他某種格式的數據時(如json、xml等)使用; 不在springMvc中配置json的處理的話,我們通常會在Controller層中獲取到數據之後進行類型轉化,將數據轉成json字元串,比如調用fastjson進行轉化,如下 這 ...
  • 手把手教你寫網路爬蟲(4) 作者:拓海 摘要:從零開始寫爬蟲,初學者的速成指南! 封面: 上期我們理性的分析了為什麼要學習Scrapy,理由只有一個,那就是免費,一分錢都不用花! 咦?怎麼有人扔西紅柿?好吧,我承認電視看多了。不過今天是沒得看了,為了趕稿,又是一個不眠夜。。。言歸正傳,我們將在這一期 ...
  • 在進行網頁數據抓取時我們要先安裝一個模塊 requests 通過終端安裝如下圖 因為我之前安裝過了,所以不會顯示安裝進度條,安裝也非常簡單,如果你配置好環境變數的話,你只需要執行以下命令 如果提示要升級,就按下麵升級pip 安裝完模塊後我們正式開始進行數據爬取 先說一下requests的用法,導入這 ...
  • 用for迴圈對無序數組進行排序輸出。 public class BubbleSort{ public static void main (String [] args){ int a[] = {21,9,45,17,33,72,50,12,41,39}; for (int i=a.length; - ...
  • MyBatis—Spring 項目 目前大部分的 Java 互聯網項目,都是用 Spring MVC + Spring + MyBatis 搭建平臺的。 使用 "Spring IoC" 可以有效的管理各類的 Java 資源,達到即插即拔的功能;通過 "Spring AOP" 框架,資料庫事務可以委托 ...
  • 內容:日曆對象獲取時間,設置時間,日期偏移 通過工廠化獲得對象。getInstance();get() 獲取時間信息 美國的星期是從星期天開始的,所以會有點問題set()設置方法,設置時間 //解答三月一日的前一天就是 Calendar c = Calendar.getInstance(); int ...
  • 集合的迭代器 任何集合都有迭代器。 任何集合類,都必須能以某種方式存取元素,否則這個集合容器就沒有任何意義。 迭代器,也是一種模式(也叫迭代器模式)。在java中它是一個對象,其目的是遍歷並選中其中的每個元素,而使用者(客戶端)無需知道裡面的具體細節。迭代器要足夠的“輕量”——創建迭代器的代價小。所 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...