基于Python实现的四则运算生成程序,,Github项目地址


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实现的四则运算生成程序

评论关闭