實現四則運算 (python實現)by 周乃君 張宏根


  GitHub項目地址:https://github.com/qq1040673290/untitled2/blob/master/myapp.py 

1.功能要求

題目:實現一個自動生成小學四則運算題目的命令行程序

  1. 使用 -n 參數控制生成題目的個數
  2. 使用 -r 參數控制題目中數值(自然數、真分數和真分數分母)的范圍,該參數可以設置為1或其他自然數。該參數必須給定,否則程序報錯並給出幫助信息
  3. 生成的題目中計算過程不能產生負數,也就是說算術表達式中如果存在形如e1 − e2的子表達式,那么e1 ≥ e2
  4. 生成的題目中如果存在形如e1 ÷ e2的子表達式,那么其結果應是真分數
  5. 每道題目中出現的運算符個數不超過3個
  6. 程序一次運行生成的題目不能重復,即任何兩道題目不能通過有限次交換+和×左右的算術表達式變換為同一道題目。例如,23 + 45 = 和45 + 23 = 是重復的題目,6 × 8 = 和8 × 6 = 也是重復的題目。3+(2+1)和1+2+3這兩個題目是重復的,由於+是左結合的,1+2+3等價於(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重復的兩道題,因為1+2+3等價於(1+2)+3,而3+2+1等價於(3+2)+1,它們之間不能通過有限次交換變成同一個題目。生成的題目存入執行程序的當前目錄下的Exercises.txt文件
  7. 在生成題目的同時,計算出所有題目的答案,並存入執行程序的當前目錄下的Answers.txt文件
  8. 程序應能支持一萬道題目的生成
  9. 程序支持對給定的題目文件和答案文件,判定答案中的對錯並進行數量統計,統計結果輸出到文件Grade.txt (未實現)

2.PSP

PSP2.1 Personal Software Process Stages 預估耗時(分鍾) 實際耗時(分鍾)
Planning 計划 60 90
· Estimate · 估計這個任務需要多少時間 60 90
Development 開發 1720 2070
· Analysis · 需求分析 (包括學習新技術) 200 250
· Design Spec · 生成設計文檔 50 60
· Design Review · 設計復審 (和同事審核設計文檔) 20 20
· Coding Standard · 代碼規范 (為目前的開發制定合適的規范) 10 10
· Design · 具體設計 30 40
· Coding · 具體編碼 1300 1600
· Code Review · 代碼復審 50 30
· Test · 測試(自我測試,修改代碼,提交修改) 60 60
Reporting 報告 100 100
· Test Report · 測試報告 60 60
· Size Measurement · 計算工作量 10 10
· Postmortem & Process Improvement Plan · 事后總結, 並提出過程改進計划 30 30
合計   1880 2260

3.設計實現過程

       首先,建立命令行控制模塊,然后建立一個com類來生成隨機數與隨機運算符,使用list表存放隨機數與隨機運算符,通過get_Calculate()函數判斷運算符,然后通過

get_Conversion()函數進行真分數的轉換,完成運算和化簡后,通過test_save()將算式寫入Exercise文檔中並把答案寫入Answers文檔中,將算式寫入文件時進行算式的查

重,通過重復答案的索引判斷算式是否重復來實現查重功能。

4.代碼說明

1.命令控制模塊

def get_Parameter():#命令行控制模塊
    parser = argparse.ArgumentParser()
    parser.add_argument('-n', help='設定題目數量',type=int)
    parser.add_argument('-r', help='設定數值范圍',type=int)
    return parser.parse_args()

 

2.建立一個類用以生成隨機數與運算符

class com(object):
    def __init__(self, r):#初始化
        self.r=r

    def get_Arithmeticl(self):#獲得隨機數字與符號
        symbol=[]
        numerical=[]
        syb=0
        n=1
        m=0
        i=random.randint(1, 3)
        for x in range(i):
            sy=random.choice(['+','-','×','÷'])
            if sy=='+'or sy=='-':
                syb +=10**(i-x-1)
            else :
                syb += 2 * (10 ** (i - x - 1))
            symbol.append(sy)
        if self.r < 10:
            n = int(10 / self.r)
        if n==1:
            while m <= i:
                numerical.append(Fraction(random.randint(1, self.r), random.randint(1, self.r)))
                m+=1
        else:
            while m <= i:
                nu = Fraction(random.randint(1, self.r * n), random.randint(1, self.r * n))
                if nu<=self.r:
                    numerical.append(nu)
                    m += 1
        return symbol,syb,numerical,i

 

3.識別運算符和分數的轉換

def get_Calculate(a,b,c):#四則運算
    if c=='+':
        results=a+b
    elif c=='-':
        results=a-b
    elif c=='×':
        results=a*b
    else:results=a/b
    return results

def get_Conversion(fraction):#假分數轉化真分數
    if fraction.numerator%fraction.denominator==0:
        return '%d'%(fraction.numerator/fraction.denominator)
    elif fraction.numerator>fraction.denominator:
        a=int(fraction.numerator/fraction.denominator)
        b, c = fraction.numerator - a * fraction.denominator, fraction.denominator
        return '%d%s%d%s%d' % (a,'',b,'/',c)
    else:
        b, c = fraction.numerator, fraction.denominator
        return '%d%s%d' % (b,'/',c)

 

4.生成算式列表和查重

ef get_Formula(n,r):#生成題目和答案列表
    Exercises,Answers,Exercises1,Exercises2=[],[],[],[]
    x=1
    while x<n+1:
        symbol, syb, numerical,i = com(r).get_Arithmeticl()
        results = numerical[0]
        judge = True
        for y in range(i):
            calculate=get_Calculate(results,numerical[y+1],symbol[y])
            if calculate>=0:#判斷算式是否合法
                answer=calculate
            else:
                judge=False
                break
        if judge:#查重
            try:
                num=Answers.index(answer)#判斷重復答案的索引
                if operator.eq(Exercises1[num],symbol) and operator.eq(Exercises2[num],numerical):
                    pass
            except ValueError as e:#可以寫入
                Answers.append(answer)
                Exercises1.append(symbol)
                Exercises2.append(numerical)
                Exercises.append('%d. %s'%(x,set_Formula(symbol,numerical,syb)))
                x+=1
        else:pass
    return Exercises,Answers

5.寫入文件

def text_save(filename, data):#filename為寫入文件的路徑,data為要寫入數據列表.
    file = open(filename,'a')
    file.seek(0)
    file.truncate() # 清空文件
    for x in data:
        x='%s\n'%(x)
        file.write(x)
    file.close()
    print('%s文件保存成功'%filename)

6.main函數

def main():
    args = get_Parameter()
    if args.n:
        n = args.n
    if args.r:
        r = args.r
        Exercises, Answers = get_Formula(n, r)
        for x in range(n):
            Answers[x] = '%d. %s' % (x + 1, get_Conversion(Answers[x]))
        print('本次共生成題目%d道\n題目數值范圍為0-%d' % (n, r))
        text_save('Exercises.txt', Exercises)
        text_save('Answers.txt', Answers)

 

5.測試結果分析:

 

程序運行:

 

 生成文件:

 

生成10000道題目文件:

 

6.項目總結

       本次項目為結對項目,這次題目比上次難了許多,一開始對項目框架的構建比較模糊,經過一段時間的查詢資料與討論后我們進行了項目分工,做項目時,一個人進行編寫另一個人在旁邊指導和構思,我們在設計功能時會提出各自的想法,經過討論選擇更合適的方法。其中在查重和統計答案對錯的功能實現遇到了困難,之后我們決定使用通過重復答案去查找相同的式子來完成查重,由於我們的編程基礎較為薄弱,未能實現對答案的統計對錯功能。結對編程之后,我感受到了結對編程的優點在於,在編寫代碼的過程中,結對伙伴會在旁邊找出編碼的錯誤,並能較快的找到BUG,讓我們能及時修改代碼,這樣提高了編程效率,節約時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM