一、题目描述:

1. 使用 -n 参数控制生成题目的个数,例如

Myapp.exe -n 10 -o Exercise.txt

将生成10个题目。

2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如

Myapp.exe -r 10

将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。

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

4. 每道题目中出现的运算符个数不超过3个。

5. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,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文件,格式如下:

1. 四则运算题目1

2. 四则运算题目2

……

其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

6. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:

1. 答案1

2. 答案2

特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

7. 程序应能支持一万道题目的生成。

8. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,并会输出所有题目中重复的题目,输入参数如下:

Myapp.exe -e .txt -a .txt -o Grade.txt

        统计结果输出到文件Grade.txt,格式如下:

        Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
Repeat:2
RepeatDetail:
(1) 2,45+32 Repeat 3,32+45
(2) 5,3+(2+1) Repeat 7,1+2+3

二、分析设计

1.生成随机表达式

需要生成随机数(整数,分数,带分数)的函数,随机运算符的函数,随机添加括号函数,采用String拼接生成随机表达式。

2.表达式处理计算

将中缀表达式转换为后缀表达式,对后缀表达式进行分割处理,通过栈操作进行运算,由于存在分数和带分数,需通过自定义四则运算法则进行计算,具体为同化成分数进行运算,完成后需约分。

3.表达式查重

先通过读取答案文档,扫描相同答案的表达式进行判断,可提高效率,接着再将相同答案的中缀表达式转换成后缀表达式,判断所有元素是否相等。此方法效率较高,但存在局限性。由于本人并不是通过二叉树处理表达式,再使用二叉树显得 很繁琐,且效率不高。

4.输出至文档

需要输出的文档有表达式Exercises.txt,答案Answers.txt,成绩及查重结果Grade.txt。

三、功能实现

    1.主程序Main.java
主要代码:
System.out.println("---------------四则运算程序---------------");
System.out.println("-n:生成题目个数");
System.out.println("-r:参数数值范围");
System.out.println("-g:查看测试结果");
System.out.println("Do:执行程序");
System.out.println("请输入指令:");
Scanner in =new Scanner(System.in);
while(in.hasNext()){
switch(in.next()){
case "-n" :
System.out.println("请输入要生成的题目个数:");
n=in.nextInt();
break;
case "-r":
System.out.println("请输入运算数的数值范围:");
m=in.nextInt();
break;
case "-g":
fo.FileC(file2, file3, file4); //答案和做题文档对比,结果写入Grade文档
break;
case "Do":
for(int i=0;i<n;i++){
String s=ex.CreatExp(n,m),fstr; //生成随机表达式并求解
String rus=its.suffixToArithmetic(its.infixToSuffix(s)); fstr=i+1+":"+s+"\r\n";
fo.FileW(file1, fstr); //表达式写入文档 fstr=i+1+":"+rus+"\r\n";
fo.FileW(file2, fstr); //答案写入文档
}
break;
default:
System.out.println("无效指令!");
break;
}
System.out.println("请输入指令:"); 2.随机表达式生成
主要代码:
/*随机生成表达式*/
public String CreatExp(int n ,int m){
String exp=CreatNum(m); //随机操作数
Random rd=new Random();
int t=rd.nextInt(2);
boolean flag=false; //是否生成括号
if(t>0)
flag=Creatkh();
for(int i=0;i<=t;i++){ //生成String类型中缀表达式
if(flag==true){
if(i==0){
exp=exp+CreatChar()+"("+CreatNum(m);
}else
{
exp=exp+CreatChar()+CreatNum(m)+")";
}
}else{
exp=exp+CreatChar()+CreatNum(m);
}
}
return exp;
} /*随机生成操作数*/
public String CreatNum(int m){
String s="";
Random rd=new Random();
switch(rd.nextInt(2)){ //随机类型:整数,分数
case 0:
s=Integer.toString(rd.nextInt(m-1)+1); //整数
break;
case 1: //分数
int a,b;
a=rd.nextInt(m-1)+1;
b=rd.nextInt(m-2)+2;
s=Dating(a,b); //分数约分处理
break;
}
return s;
} /*随机生成运算符*/
public String CreatChar(){
String s="";
Random rd=new Random();
switch(rd.nextInt(4)){
case 0:s="+";break;
case 1:s="-";break;
case 2:s="*";break;
case 3:s="÷";break;
}
return s;
} /*分数进行约分*/
public String Dating(int a,int b){
String s="";
int gongyinshu=1,c;
c=a/b;
a=a%b;
if(c<0){ //若带分数已为负数,这分数不用带负号
a=a*-1;
}
for (int i = 1; i <= a; i++) { //求最小公约数
if (a % i == 0 && b % i == 0) {
gongyinshu = i;
}
}
a=a/gongyinshu; //生成最简分数
b=b/gongyinshu;
if(a==0){
s=Integer.toString(c);
}else if(c==0){
s=Integer.toString(a)+"/"+Integer.toString(b);
}else{
s=Integer.toString(c)+"'"+Integer.toString(a)+"/"+Integer.toString(b);
}
return s;
} /*随机是否生成括号*/
public boolean Creatkh(){
boolean flag=false;
Random rd=new Random();
if(rd.nextInt(3)<1) //生成扩号的概率为1/3
flag=true;
return flag;
} 3.表达式处理
主要代码:
/*中缀表达式转后缀表达式*/
public String infixToSuffix(String exp) {
Stack<Character> s = new Stack<Character>(); // 创建操作符堆栈
String suffix = ""; // 要输出的后缀表达式字符串
int length = exp.length(); // 输入的中缀表达式的长度
for (int i = 0; i < length; i++) {
char temp;
char ch = exp.charAt(i); // 获取该中缀表达式的每一个字符并进行判断
switch (ch) {
case '(':
s.push(ch);
break;
case '+': // 碰到'+' '-',将栈中的所有运算符全部弹出去,直至碰到左括号为止,输出到队列中去
case '-':
suffix += " ";
while (s.size() != 0) {
temp = s.pop();
if (temp == '(') {
s.push('(');
break;
}
suffix += temp;
suffix += " ";
}
s.push(ch);
break;
case '*': // 如果是乘号或者除号,则弹出所有序列,直到碰到加好、减号、左括号为止,最后将该操作符压入堆栈
case '÷':
suffix += " ";
while (s.size() != 0) {
temp = s.pop();
if (temp == '+' || temp == '-' || temp == '(') {
s.push(temp);
break;
} else {
suffix += temp;
suffix += " ";
}
}
s.push(ch);
break;
case ')':
while (!s.isEmpty()) {
temp = s.pop();
if (temp == '(') {
break;
} else {
suffix += " ";
suffix += temp;
}
}
break;
default:
suffix += ch;
break;
}
}
while (s.size() != 0) { // 如果堆栈不为空,则把剩余运算符一次弹出,送至输出序列
suffix += " ";
suffix += s.pop();
}
return suffix;
} /*计算后缀表达式*/
public String suffixToArithmetic(String exp) {
String[] strings = exp.split(" "); //按空格分解字符串
Stack<String> stack = new Stack<String>(); //操作数栈
for (int i = 0; i < strings.length; i++) {
if(strings[i].equals("+")||strings[i].equals("-")||strings[i].equals("*")||strings[i].equals("÷")){
String y=stack.pop(); //读取到运算符,提取栈顶的两个操作数,先出的操作数为运算符后的数
String x=stack.pop();
String rus=calculate(x, y, strings[i]); //调用自定义的四则运算法则
stack.push(rus);
if(rus.equals("无解")) //除数为0返回无解
return rus;
}else{
stack.push(strings[i]);
}
}
return stack.pop();
} /*自定义四则运算法则*/
public String calculate(String x, String y, String ch) {
}
注:四则运算过程代码较多,不展示。 4.文件操作及表达式查重代码不展示

四、结果展示

命令选择:



表达式文档:



答案文档:



答题文档:



成绩文档:



一万道题测试:



五、实验小结

此次编程要点在于表达式的处理,重点是对分数,带分数的处理,具体解决方法是将其每个部分的整数提取出来,存于几个参数中,通过参数间的转化运算达到分数的计算,从而实现表达式的计算。过程中遇到挺多小问题,例如除数为0,6÷(3-3) ,解决方法为计算除法时,进行判断,如果除数为0直接返回结果“无解”。

六 、PSP表

    PSP2.1	Personal Software Process Stages  Time Senior Student  Time
Planning 计划 2 2
Estimate 估计这个任务需要多少时间 48 36
Development 开发 40 36
Analysis 需求分析 (包括学习新技术) 2 1
Design Spec 生成设计文档 1 1
Design Review 设计复审 2 1
Coding Standard 代码规范 0 0
Design 具体设计 3 4
Coding 具体编码 27 22
Code Review 代码复审 2 1
Test 测试(自我测试,修改代码,提交修改 2 4
Reporting 报告 1 2

七、源代码

码云项目地址:https://gitee.com/liangs96_master/FourOperations

四则运算程序(java基于控制台)的更多相关文章

  1. java实现四则运算应用(基于控制台)

    项目地址:https://gitee.com/wxrqforever/object_oriented_exp1.git 一.需求分析: 一个基于控制台的四则运算系统,要能实现生成并计算含有真,假分数, ...

  2. Golang、Php、Python、Java基于Thrift0.9.1实现跨语言调用

    目录: 一.什么是Thrift? 1) Thrift内部框架一瞥 2) 支持的数据传输格式.数据传输方式和服务模型 3) Thrift IDL 二.Thrift的官方网站在哪里? 三.在哪里下载?需要 ...

  3. Java基于opencv实现图像数字识别(五)—投影法分割字符

    Java基于opencv实现图像数字识别(五)-投影法分割字符 水平投影法 1.水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像): 2.选出一个最优的阀值,根据比这个阀值大或小 ...

  4. Java基于opencv实现图像数字识别(四)—图像降噪

    Java基于opencv实现图像数字识别(四)-图像降噪 我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类 这个工具类呢,就一个成员变量 ...

  5. Java基于opencv实现图像数字识别(三)—灰度化和二值化

    Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...

  6. Java基于opencv实现图像数字识别(二)—基本流程

    Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要 ...

  7. Java基于opencv实现图像数字识别(一)

    Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用Buffere ...

  8. Java基于ssm框架的restful应用开发

    Java基于ssm框架的restful应用开发 好几年都没写过java的应用了,这里记录下使用java ssm框架.jwt如何进行rest应用开发,文中会涉及到全局异常拦截处理.jwt校验.token ...

  9. Java基于注解和反射导入导出Excel

    代码地址如下:http://www.demodashi.com/demo/11995.html 1. 构建项目 使用Spring Boot快速构建一个Web工程,并导入与操作Excel相关的POI包以 ...

随机推荐

  1. 用SpeedFan来控制CPU风扇转速

    用SpeedFan来控制CPU风扇转速 浏览:63252 | 更新:2011-04-07 21:14 1 2 3 4 5 6 7 分步阅读 原创文章:看到SpeedFan,很多朋友最想要的是用Spee ...

  2. 芝麻HTTP:非关系型数据库存储

    NoSQL,全称Not Only SQL,意为不仅仅是SQL,泛指非关系型数据库.NoSQL是基于键值对的,而且不需要经过SQL层的解析,数据之间没有耦合性,性能非常高. 非关系型数据库又可细分如下. ...

  3. freemarker处理map的数据(二十)

    1.简易说明 (1)map取值 (2)key取值 2.实现示例 <html> <head> <meta http-equiv="content-type&quo ...

  4. 关于js中 toFixed()的一个小坑

    作为一名前端,大家都应该知道,toFixed()的作用,toFixed()经常用于前台与后台数据格式的转换,套用下w3c上面的定义: 定义和用法toFixed(n) 方法可把 Number 四舍五入为 ...

  5. hive查询结果输出到hdfs上

    insert overwrite directory "/mapredOutput/UserYesterdayInterest/${hiveconf:day}"row format ...

  6. 《C#图解教程》 总览

    初识本书是在知乎,许多网友推荐它作为 C# 入门书籍. 本书的最大特点是插图丰富,许多复杂的概念,一副插图就解释得通透明了. 本书另外一个隐藏特性是作者有着 C/C++ 经验,书中经常提到它们与 C# ...

  7. 关于ThinkCMF自带插件上传不了图片的解决方法

    第一个原因:第一次安装的时候提示file_upload未打开,所以当上传的时候回上传失败 解决方法:在php.ini里打开file_uploads = On 第二个原因:一开始还可以上传,但是当删除了 ...

  8. 【洛谷2986】【USACO10MAR】伟大的奶牛聚集

    题面 题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of co ...

  9. 内嵌tomcat启动速度慢

    项目上最近要把内置的jetty换成tomcat, 来更好的支持servlet 3.0 本来以为换个容器, 几十行代码就好了. 实际上换了tomcat后, 一开始启动tomcat, 非常的慢. jett ...

  10. python多线程、多进程以及GIL

    多线程 使用threading模块创建线程 传入一个函数 这种方式是最基本的,即调用threading中的Thread类的构造函数,然后指定参数target=func,再使用返回的Thread的实例调 ...