实现四则运算 (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