四则运算

项目要求:

题目:实现一个自动生成小学四则运算题目的命令行程序说明:

说明:

自然数:0, 1, 2, …。

真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。

运算符:+, −, ×, ÷。

括号:(, )。

等号:=。

分隔符:空格(用于四则运算符和等号前后)。

算术表达式:

e = n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),

其中e, e1和e2为表达式,n为自然数或真分数。

四则运算题目:e = ,其中e为算术表达式。

需求:

1.(完成)使用 -n 参数控制生成题目的个数

2.(完成)使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,该参数可以设置为1或其他自然数。

3.(完成)生成的题目中计算过程不能产生负数

4.(完成)生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数

5.(完成)每道题目中出现的运算符个数不超过3个。

6.(完成)程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。生成的题目存入执行程序的当前目录下的Exercises.txt文件

7.(完成)在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件

8.(完成)程序应能支持一万道题目的生成。

9.(完成)程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。统计结果输出到文件Grade.txt,格式如下:

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

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

设计实现过程

总体构思:

表达式:

将整数也看作分数来生成随机数,为Fraction类型,有numerator,denominator两个属性,然后根据运算符个数生成表达式,如:A+B*C/D。

再转换成逆波兰表达式,然后转化成规范化的二叉树如:随机生成表达式:2*6+5*7 à 逆波兰表达式:26*57*+ , 再转化成二叉树的同时进行规范化并计算结果存入树的value属性中:

二叉树的叶子节点都为数字,非叶子节点都为运算符,当规范化二叉树时,其实是遍历逆波兰式列表中的元素,然后创建一个空树,若遍历到的元素不是运算符,就将数字添加入树的属性,并将树存入列表stack中,若是运算符,则弹出列表中后两个树t2、t1,此时两个树中情况无非是

1. 2.

3.

4.

通过计算比较value值(有运算符则为两数运算后的值,不论是什么运算符,都为t1 op t2,并非左子树 op 右子树)将vlaue较大的设为左子树并计算新的value,若value值相等,则通过判定优先级来确定左右子树。

负数与除数为0:

负数的产生是由于t1 < t2,同时若在进行减法后的值为0且做除数,则出现除数为0情况,所以通过条件判断舍弃在运算符为“-”时,t1 <= t2 的二叉树

判断表达式是否重复

转换成规范二叉树,然后再以逆波兰格式转成字符串形式,存在一个列表里,每次生成了一个新式子后,就按上面方法生成规范化的二叉树并转成逆波兰形式字符串与列表中所有元素比较。

例如2*6+5*7与7*5+6*2生成的规范化二叉树都为:

其返回的字符串逆波兰式相同,即2*6+5*7与7*5+6*2是一样的表达式。

主要的类和函数有:

class Arith(object)

creat(self, problem_number, r) # 生成四则运算和答案在判重后写入文件

main(self, arith, argv) # 支持命令行输入参数

class BinaryTree(object) # 二叉树

out_put_tree(self, tree, s) # 返回二叉树逆波兰形式的字符串

class Caculation(object)

caulate(self, op, f1, f2) # 计算f1 op f2 的值(op为运算符)

max(self, num1, num2) # 比较两分数大小

class Check(object) # 判重

check_tree(self, tree) # 对二叉树进行判重,若不重复返回True

class Compare(object)

grade(self, exercise_file, answer_file) # 比较两文件答案并记录

class Create(object) # 生成四则运算表达式

create_operator(self) # 随机生成运算符

create_arith(self, r) # 生成范围在r以内的四则运算表达式

proper_fraction(self, list) # 将假分数化为带分数

class Fractions(object) # 分数类

class CreateTree(object) # 生成规范二叉树

toRPN(self, list) # 生成逆波兰表达式

createTree(self, suffix) # 将逆波兰式转化为规范化二叉树

priority(self, operatorout, operatorin) # 判定优先级

代码说明:

生成四则运算表达式:

defcreate_arith(self, r):

x=0

list=[]

operator_num= random.randint(1, 3)

e1=Create()

e2=Create()if operator_num == 1:

list.append(e1.create_number(r))

list.append(e2.create_operator())

list.append(e1.create_number(r))elif operator_num == 2:

start= random.randint(0, 2)

end=0if start >0:

end= start + 1

for i in range(1, 4):if i ==start:

list.append("(")

list.append(e1.create_number(r))if i ==end:

list.append(")")

list.append(e2.create_operator())

list.pop()elif operator_num == 3:

start= random.randint(0, 3)

end=0if start >0:

end= start + 1 + random.randint(0, 1)if end >= 4:

end= 4

for i in range(1, 5):if i ==start:

list.append("(")

list.append(e1.create_number(r))if i ==end:

list.append(")")

list.append(e2.create_operator())

list.pop()else:

list.append(e1.create_number(r))

list.append(e2.create_operator())

list.append(e1.create_number(r))return list

假分数化为带分数:

#将表达式假分数转化为带分数

defproper_fraction(self, list):

num=0for fract inlist:if type(fract) ==Fraction:

n1=fract.numerator

n2=fract.denominatorif n2 == 1:

num+= 1

continue

elif n1 >n2:

sub= int(n1/n2)

n1= n1 %n2

list[num]= '%d%s%d/%d' %(sub, '’', n1,n2)

num+= 1

returnlist#将答案假分数转化为带分数

defpop_fracte(self, re):

n1=re.numerator

n2=re.denominatorif n2 == 1:returnn1elif n1

sub= int(n1/n2)

n1= n1 %n2return '%d%s%d/%d' % (sub, '’', n1, n2)

生成逆波兰式:

deftoRPN(self, list):

right=[]

aStack=[]

position=0whileTrue:ifself.isOperator(list[position]):if list == [] or list[position] == "(":

aStack.append(list[position])else:if list[position] == ")":whileTrue:if aStack != [] and aStack[-1] != "(":

operator=aStack.pop()

right.append(operator)else:if aStack !=[]:

aStack.pop()break

else:whileTrue:if aStack != [] and self.priority(list[position], aStack[-1]):

operator=aStack.pop()if operator != "(":

right.append(operator)else:breakaStack.append(list[position])else:

right.append(list[position])

position= position + 1

if position >=len(list):break

while aStack !=[]:

operator=aStack.pop()if operator != "(":

right.append(operator)return right

将逆波兰式转化成规范化的二叉树:

defcreateTree(self, suffix):

stacks=[]for i inrange(0, len(suffix)):

tree=BinaryTree()

ob=suffix[i]

c=Caculation.Caculation()ifself.isOperator(ob):

t2=BinaryTree()

t1=BinaryTree()

t2=stacks.pop()

t1=stacks.pop()if ob == '-' and t1.value <=t2.value:returnNoneelse:ifself.maxTree(t1, t2):

tree.set_date(ob)

tree.set_left(t1)

tree.set_right(t2)

tree.set_value(c.caulate(ob, t1.value, t2.value))else:

tree.set_date(ob)

tree.set_left(t2)

tree.set_right(t1)

tree.set_value(c.caulate(ob, t1.value, t2.value))

stacks.append(tree)else:

tree.set_value(ob)

tree.set_date(ob)

stacks.append(tree)return tree

对二叉树判重:

#对二叉树进行判重

defcheck_tree(self, tree):if self.check ==[]:

self.check.append(tree)returnTrueelse:for i inrange(len(self.check)):if self.check[i] ==tree:returnFalse

self.check.append(tree)return True

二叉树类:

classBinaryTree(object):def __init__(self):

self.date=None

self.left=None

self.right=None

self.value=Nonedeftree(self, date, left, right, value):

self.date=date

self.left=left

self.right=right

self.value=valuedefset_date(self, date):

self.date=datedefset_left(self, left):

self.left=leftdefset_right(self, right):

self.right=rightdefset_value(self, value):

self.value=valuedefto_string(self, tree):

s= ""s=self.out_put_tree(tree, s)returnsdefout_put_tree(self, tree, s):if tree !=None:

s1=self.out_put_tree(tree.left, s)

s2=self.out_put_tree(tree.right, s)if type(tree.date) ==Fractions.Fractions:return str(s1) + str(s2) +str(tree.date.to_string())else:return str(s1) + str(s2) +str(tree.date)return s

分数类:

classFractions(object):def __init__(self):

self.numerator=None

self.denominator=NonedefsetNumerator(self,numerator):

self.numerator=numeratordefsetDenominator(self,denominator):

self.denominator=denominatordeftoString(self):

a=self.numerator

b=self.denominatorreturn str(Fraction(a, b))

计算参数值:

defcaulate(self, op, f1, f2):

result=Fractions.Fractions()

n1=int(f1.numerator)

d1=int(f1.denominator)

n2=int(f2.numerator)

d2=int(f2.denominator)

list=[]if op == '+':

re= Fraction(n1, d1) +Fraction(n2, d2)elif op == '-':

re= Fraction(n1, d1) -Fraction(n2, d2)elif op == '×':

re= Fraction(n1, d1) *Fraction(n2, d2)else:

re= Fraction(n1, d1) /Fraction(n2, d2)return re

文件比较,判断错误答案并记录:

#对两个文件中的答案进行比较并记录

defgrade(self, exercise_file, answer_file):

correct=[]

wrong=[]

co=0

wr=0

with open(answer_file,'r') as f1, open(exercise_file, 'r', encoding='utf-8') as f2:

answers=f2.readlines()

line=0for r_answers inf1.readlines():if answers[line] ==r_answers:

co+= 1correct.append(line+1)else:

wr+= 1wrong.append(line+1)

line+= 1with open('gread.txt', 'w') as f3:

f3.write(f"Correct: {str(co)} ({', '.join(str(s) for s in correct if s not in [None])})" + '\n')

f3.write(f"Correct: {str(wr)} ({', '.join(str(s) for s in wrong if s not in [None])})" + '\n')print("文件比较完成")

生成表达式判重后写入文件:

#生成问题和答案在判重后写入文件

defcreat(self, problem_number, r):

creat_pro=CreatProblem.Create()

t=BinaryTree.BinaryTree()

c=Check.Check()

with open("Exercises.txt", "w") as file1, open("Answer.txt", "w") as file2:

num=0while num

arith= creat_pro.create_arith(r) #生成四则运算列表

Ju =CreateTree.Judge()

al= Ju.toRPN(arith) #将列表转换成逆波兰式

print(al)

string=creat_pro.to_string(creat_pro.proper_fraction(arith))

ta= Ju.createTree(al) #将逆波兰式生成规范二叉树

print(t.to_string(ta))ifta:

val=str(creat_pro.pop_fracte(ta.value))if c.check_tree(t.to_string(ta)): #进行判重

file1.write("%d." % (num+1) + string + '\n')

file2.write("%d." % (num+1) + val + '\n')

num+=1

print("四则运算题目生成完毕,数量为%d个" % problem_number)

命令行程序入口:

#支持命令行键入参数

defmain(self, arith, argv):

problem_number=None

num_range=None

exercise_file=None

answer_file=Nonetry:

opts, args= getopt.getopt(argv, "n:r:e:a:")exceptgetopt.GetoptError:print('Error: arith.py -n -r ')print('or: test_arg.py -e -e .txt -a .txt')

sys.exit(2)for opt, arg inopts:if opt in("-n"):

problem_number=int(arg)elif opt in ("-r"):

num_range=int(arg)elif opt in("-e"):

exercise_file=argelif opt in("-a"):

answer_file=argif problem_number andnum_range:

arith.creat(problem_number, num_range)elif exercise_file andanswer_file:

compare=Compare.Compare()

compare.grade('ReAnswer.txt', 'Answer.txt')else:print('Error: arith.py -n -r ')print('or: test_arg.py -e -e .txt -a .txt')

测试运行

参数错误提示

生成10道题的题目与答案

文件答案比较

生成一万道题目

以下为一万到题目和答案的链接

PSP

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

60

80

· Estimate

· 估计这个任务需要多少时间

50

50

Development

开发

900

800

· Analysis

· 需求分析 (包括学习新技术)

40

80

· Design Spec

· 生成设计文档

60

60

· Design Review

· 设计复审 (和同事审核设计文档)

20

30

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

30

30

· Design

· 具体设计

60

180

· Coding

· 具体编码

500

800

· Code Review

· 代码复审

100

120

· Test

· 测试(自我测试,修改代码,提交修改)

120

150

Reporting

报告

60

90

· Test Report

· 测试报告

30

30

· Size Measurement

· 计算工作量

20

30

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

20

20

合计

2070

2550

项目小结:

在本次结点编程四则运算项目中,与杨浩政同学一起组队讨论写代码。首先呢,我们一起讨论如何实现这个项目,共同讨论书写设计文档。在写设计文档的过程中,我们很多想法都不一样,由于我的编程水平比较低,缺乏经验,一般来说,都是以杨浩政同学的想法为主,我的想法为辅。在交流设计思路的过程中,我们两人的思维也会碰撞出更好的解决思路。在双方都认为自己的想法比较好时,会各自说出自己想法的优点,然后再共同思考哪个实现途径更优。最大的感触是:多听听不同的想法,会使自己的思维更开阔。(来自张兆敏同学的小结)

本次结对编程我主要负责代码实现,这次编程对我的帮助很大,让我明白了只有思路足够清晰才能更快更好地实现功能,在拿到项目后一定要多思考如何实现更简洁方便,而不是边写边想,到最后不停修改。与队友的讨论也启发了我一些思路,只要思路上能找到合适的方法,那么实现起来就会容易快速很多。(来自杨浩政的小结)

python实现四则运算_四则运算 Python实现(杨浩政,张兆敏)相关推荐

  1. python 时间序列预测_使用Python进行动手时间序列预测

    python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...

  2. python 概率分布模型_使用python的概率模型进行公司估值

    python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...

  3. 怎样用python自动化办公_会python基础,如何学习自动化办公?

    Python 自动化,爽爽的解决 本课程完全让你摒弃重复率高,机械操作的劳动,解放双手,自动化办公,比如Excel表的各种计算,合并,比对,尤其是跨表,大量数据的,连Excel打开都费劲的,Pytho ...

  4. python集群_使用Python集群文档

    python集群 Natural Language Processing has made huge advancements in the last years. Currently, variou ...

  5. python 网页编程_通过Python编程检索网页

    python 网页编程 The internet and the World Wide Web (WWW), is probably the most prominent source of info ...

  6. python机器学习预测_使用Python和机器学习预测未来的股市趋势

    python机器学习预测 Note from Towards Data Science's editors: While we allow independent authors to publish ...

  7. python高斯求和_利用Python进行数据分析(3)- 列表、元组、字典、集合

    本文主要是对Python的数据结构进行了一个总结,常见的数据结构包含:列表list.元组tuple.字典dict和集合set. image 索引 左边0开始,右边-1开始 通过index()函数查看索 ...

  8. python 免费空间_用python做大数据

    不学Python迟早会被淘汰?Python真有这么好的前景? 最近几年Python编程语言在国内引起不小的轰动,有超越Java之势,本来在美国这个编程语言就是最火的,应用的非常非常的广泛,而Pytho ...

  9. python希腊字母字符串_#10 Python字符串

    前言 通过上一节可知,Python6个序列的内置类型中,最常见的是列表和元组,但在Python中,最常用的数据类型却不是列表和元组,而是字符串.要想深入了解字符串,必须先掌握字符编码问题.因此本篇博文 ...

最新文章

  1. Microbiome:在人工肠道中建立动态线性模型指导设计和分析微生物组研究
  2. 2022互联网大厂薪资大比拼
  3. Linux Shell常用技巧(三) sed
  4. java循环购物车结算系统_原生JS实现购物车结算功能代码
  5. python装饰器类-python_类装饰器
  6. Spring Boot 2.X 使用@Cacheable时注意事项
  7. java ee me se_java EE ME SE有什么关系
  8. 计算机一开机会做什么,新电脑开机需要做什么
  9. jsp怎么接受ajax请求参数,通过ajax发送JSON并通过JSP中的请求获取参数
  10. 每一个创业的人,你要解决的就是流量
  11. 处理异常:org.springframework.beans.factory.BeanNotOfRequiredTypeException
  12. 全球经典《深入解析Windows 操作系统,第4 版》4月19日全国发货!
  13. c语言调用DOS命令删除文件,DOS删除命令怎么使用?用DOS命令删除文件的方法
  14. base64格式的pdf预览
  15. 数学建模 matlab MATLAB机器学习 分类方法 支持向量机分类 乳腺癌的诊断
  16. C语言应用(2)——判断当前时间是否在一个时间段内(含跨天)
  17. layui多文件一次性上传案例
  18. JAVA虚拟机、Dalvik虚拟机和ART虚拟机
  19. word打开wps文件乱码_Word打开WPS文档成乱码怎么办
  20. 大学计算机课外知识教案,大学计算机论文精选范文

热门文章

  1. powershell:调用7z,haozip解压缩文件
  2. uboot的常用环境变量(bootdelay、ipaddr、serverip、gatewayip、netmask、ethaddr、bootcmd、bootargs)
  3. 删除eclipse的SVN/Subclipse插件
  4. Xbox One手柄
  5. 心电 基线漂移的处理研究论文
  6. Deeplearning for NLP (简介)
  7. MAC MacVim及Vundle安装
  8. graythresh
  9. 关于‘云’,你可能要知道的“私有”和“公有”!!!
  10. 14寸android触摸屏,14寸触摸屏的使用寿命