1. 程式人生 > >基於Python實現的四則運算生成程序

基於Python實現的四則運算生成程序

個人 目錄 [] class 是否 time 除法 slist 設計實現

Github項目地址:傳送門

小組成員:黃曉彬(代碼實現) 黃鈺城(代碼審查)

需求:

1. 使用 -n 參數控制生成題目的個數。

2. 使用 -r 參數控制題目中數值(自然數、真分數和真分數分母)的範圍。

3. 生成的題目中計算過程不能產生負數,也就是說算術表達式中如果存在形如e1 ? e2的子表達式,那麽e1 ≥ e2

4. 生成的題目中如果存在形如e1 ÷ e2的子表達式,那麽其結果應是真分數。

5. 每道題目中出現的運算符個數不超過3個。

6. 程序一次運行生成的題目不能重復,

生成的題目存入執行程序的當前目錄下的Exercises.txt文件。

7. 在生成題目的同時,計算出所有題目的答案,並存入執行程序的當前目錄下的Answers.txt文件。

8. 程序應能支持一萬道題目的生成。

9. 程序支持對給定的題目文件和答案文件,判定答案中的對錯並進行數量統計,輸入參數如下:

Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt

統計結果輸出到文件Grade.txt,格式如下:

Correct: 5 (1, 3, 5, 7, 9)

Wrong: 5 (2, 4, 6, 8, 10)

其中“:”後面的數字5表示對/錯的題目的數量,括號內的是對/錯題目的編號。為簡單起見,假設輸入的題目都是按照順序編號的符合規範的題目。(未實現)

PSP表格:

PSP2.1

Personal Software Process Stages

預估耗時(分鐘)

實際耗時(分鐘)

Planning

計劃

30

30

· Estimate

· 估計這個任務需要多少時間

30

60

Development

開發

480

520

· Analysis

· 需求分析 (包括學習新技術)

120

200

· Design Spec

· 生成設計文檔

60

70

· Design Review

· 設計復審 (和同事審核設計文檔)

30

60

· Coding Standard

· 代碼規範 (為目前的開發制定合適的規範)

30

30

· Design

· 具體設計

60

60

· Coding

· 具體編碼

600

700

· Code Review

· 代碼復審

500

700

· Test

· 測試(自我測試,修改代碼,提交修改)

200

300

Reporting

報告

60

30

· Test Report

· 測試報告

30

30

· Size Measurement

· 計算工作量

60

30

· Postmortem & Process Improvement Plan

· 事後總結, 並提出過程改進計劃

30

40

合計

2230

2860

效能分析:算法運行過程較慢,沒有使用數據結構進行優化,並且還大量使用庫函數,導致結果運行緩慢

設計實現過程:接收命令行參數-->獲取數值和符號列表-->計算結果並生成題目和答案列表-->存入兩個txt文件

函數 功能
get_num_sym(i,r) 獲取數值列表和符號列表
calculate(a,b,s) 計算單元,a,b是數,s是符號
f(f) 分數的轉換
writeF(slist,num,hb) 生成算術表達式
getF(n,r) 用於生成題目和答案列表
save(fname, d) 用於寫入文件
main() 主函數

代碼說明:

用get_num_sym(i,r)函數循環遍歷以獲得隨機分數列表和符號列表

def get_num_sym(i,r):#獲取數值列表和符號列表
    nlist=[]#數值列表
    slist=[]#符號列表
    hb=0#判斷怎麽加括號
    l=0#判斷是否是減數運算
    for m in range(i+1):#根據i的值遍歷輸出數值列表
        nlist.append(Fraction(random.randint(1, r), random.randint(1, r)))  
    for x in range(i):
        sy=random.choice([+,-,×,÷])
        if sy==+or sy==-:
            hb +=10**(i-x-1)
        else :
            hb += 2 * (10 ** (i - x - 1))
        slist.append(sy)
        if sy==-:
            l=1
    return nlist,slist,hb,i,l

把分數轉換為整數、真分數和帶分數

def f(f):#分數的轉換
    a=f.numerator
    b=f.denominator
    if a%b==0:#為整數
        return %d%(a/b)
    elif a<b:#為真分數
        return %d%s%d % (a,/,b)
    else:#為帶分數
        c=int(a/b)
        a = a - c * b
        return %d%s%d%s%d % (c,,a,/,b)

用於四則運算

def calculate(a,b,s):#計算單元,a,b是數,s是符號
    ans=0
    if s==+:#加法運算
        ans=a+b
    elif s==-:#減法運算
        a,b=max(a,b),min(a,b)#防止結果為負數
        ans=a-b
    elif s==×:#乘法運算
        ans=a*b
    else:ans=a/b#除法運算
    return ans

生成算術表達式

def writeF(slist,num,hb):#生成算術表達式
    global j,k
    s=‘‘
    if hb>100:#符號數為3
        if j==1 and k==0:
            s = %s %s (%s %s %s) %s %s =  % (f(num[0]), slist[0],
            f(num[1]),slist[1], f(num[2]), slist[2], f(num[3]))
        elif j==1 and k==1:
            s = %s %s (%s %s (%s %s %s)) =  % (f(num[0]), slist[0],
            f(num[1]),slist[1], f(num[2]), slist[2], f(num[3]))
        elif j==0 and k==1:
            s = %s %s (%s %s %s %s %s) =  % (f(num[0]), slist[0],
            f(num[1]),slist[1], f(num[2]), slist[2], f(num[3]))
        if hb == 112 or hb ==212:          
            s = (%s %s %s %s %s) %s %s =  % (f(num[0]), slist[0],
            f(num[1]),slist[1], f(num[2]), slist[2], f(num[3]))
        elif hb == 121 or hb ==122:
            s = (%s %s %s) %s %s %s %s =  % (f(num[0]), slist[0],
            f(num[1]),slist[1], f(num[2]), slist[2], f(num[3]))
        else:
            s = %s %s %s %s %s %s %s =  % (f(num[0]), slist[0],
            f(num[1]),slist[1], f(num[2]), slist[2], f(num[3]))
    elif hb>10:#符號數為2
        if j==1 :
            s = %s %s (%s %s %s) =  % (f(num[0]), slist[0],
            f(num[1]), slist[1], f(num[2]))
        if hb == 12:
            s = (%s %s %s)%s %s =  % (f(num[0]), slist[0],
            f(num[1]), slist[1], f(num[2]))
        else:
            s = %s %s %s %s %s =  % (f(num[0]), slist[0],
            f(num[1]), slist[1], f(num[2]))
    else :#符號數為1
        s =%s %s %s =  % (f(num[0]),slist[0],f(num[1]))
    return s

生成題目和答案列表

def getF(n,r):#用於生成題目和答案列表
    E,A,E1,E2=[],[],[],[]
    global j,k
    x=1
    while x<n+1:#循環生成題目和答案列表
        i=random.randint(1, 3)#隨機獲取符號數目
        num,slist,hb,i,l=get_num_sym(i,r)
        num1=num
        legal = True
        if l==1: #用於防止除法運算出現負數           
            if  num[0]<num[1]:
                num1[0],num1[1]=num[1],num[0]
            if i>=2 and calculate(num[0],num[1],slist[0])<num[2]:
                num1[0],num1[1],num1[2]=num[2],num[0],num[1]
                j=1
            if i>=3 and calculate(calculate(num[0],num[1],slist[0]),num[2],slist[1])<num[3]:
                num1[0],num1[1],num1[2],num1[3]=num[3],num[0],num[1],num[2]
                k=1        
        ans=num1[0]
        for y in range(i):
            cal=calculate(ans,num[y+1],slist[y])
            if cal>=0:#判斷算式是否合法
                ans=cal
            else:
                legal=False
                break
        if legal:#判斷是否重復題目
            try:
                num=A.index(ans)#第一個重復答案的索引
                if operator.eq(E1[num],slist) and operator.eq(E2[num],num):
                    pass
            except ValueError as e:#可以寫入
                A.append(ans)
                E1.append(slist)
                E2.append(num1)
                E.append(%d. %s%(x,writeF(slist,num1,hb)))
                x+=1
        else:pass
    return E,A

寫入txt文件

def save(fname, d):#fname為寫入文件的路徑,d為要寫入的數據列表.
    file = open(fname,a)
    file.seek(0)
    file.truncate() #清空
    for i in range(len(d)):#循環寫入文件fname
        s = str(d[i]).replace([,‘‘).replace(],‘‘)
        s = s.replace("",‘‘).replace(,,‘‘) +\n
        file.write(s)
                  
    file.close()
    print(%s文件保存成功%fname)

主函數(包括命令行參數的實現)

def main():#主函數
    parser = argparse.ArgumentParser(description="this is auto calculator")#命令行參數控制
    parser.add_argument(-n,help=控制生成題目的個數,type=int)
    parser.add_argument(-r,help=控制題目中數值(自然數、真分數和真分數分母)的範圍,type=int)
    args = parser.parse_args()
    if args.n:
        n=args.n
        print(n值為%d%n)
    if args.r:
        r=args.r
        print(r值為%d%r)
        E, A=getF(n,r)
        for x in range(n):#循環生成答案列表
            A[x]=%d. %s%(x+1,f(A[x]))
        save(Exercises.txt,E)
        save(Answers.txt,A)

    end = time.clock()
    print(運行時間: %s %(end-start))
    
if __name__ == __main__:
    main()

測試運行:

一萬道題目生成:

技術分享圖片

技術分享圖片

技術分享圖片

項目小結:由於我們兩個Python水平有限,花了幾天都想不出到底要怎麽寫這個程序,最後還是問了同學加上網看別人寫的思路,通過先全部隨機生成分數(分數包括了自然數),在用函數區分自然數、真分數和帶分數,再用函數根據條件的不同生成不同的表達式,並通過單步循環計算出結果,最後再根據情況加括號(其實是前面忘了,後面為了這個花了很長時間),才完成了這個自動生成程序。通過這次編程,我深刻感受到自己寫Python的技術有待提高,代碼讓鈺誠看得一頭包,bug更是跟修不完似的。兩個人的編程和一個人的還是有很大的不同,意見的不統一,想法的不同都會讓我們產生分歧甚至是爭執,這種時候良好的溝通才是最重要的。

基於Python實現的四則運算生成程序