一、题目描述:

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. 查找IFileSourceFilter上的Pin

    创建了IFileSourceFilter,可IFileSourceFilter好像不是从IBaseFilter继承来的,没有EnumPins,那应该怎么查找IFileSourceFilter上的pin ...

  2. 初识Go语言

    一.Go语言的主要特性: ①    开放源代码的通用计算机编程语言.开放源代码的软件(以下简称开源软件)更容易被修正和改进. ②    虽为静态类型.编译型的语言,但go语言的语法却趋于脚本化,非常简 ...

  3. 异常-----freemarker.template.TemplateException:Error executing macro:mainSelect

    1.错误描述 freemarker.template.TemplateException:Error executing macro:mainSelect require parameter:id i ...

  4. spring mvc和swagger整合

    pom.xml 导入jar jar包 所属 备注 spring-core spring spring核心包 spring-expression spring spEl表达式 spring-beans ...

  5. java基础之二分法查找

    package p1; import java.util.*; public class Sortdob { public static void BubbleSort(int[] arr) {    ...

  6. ThreadLocal原理

    ThreadLocal类可以看作是当前线程的一个局部变量,只有当前线程可以访问,因此是线程安全的. ThreadLocal内部维护了一个ThreadLocalMap类,ThreadLocalMap是一 ...

  7. [BZOJ1070] [SCOI2007] 修车 (费用流 & 动态加边)

    Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使 ...

  8. SpringMVC常用注解整理

    一.组件型注解: @Component 在类定义之前添加@Component注解,他会被spring容器识别,并转为bean. @Repository 对Dao实现类进行注解 (特殊的@Compone ...

  9. c#多线程同步之EventWaitHandle再次使用

    /// <summary> /// 文件传输器,用来获取全文文件,自动根据全文文件数量,开启一定数量的线程,采用生产者消费模式 /// </summary> public cl ...

  10. kubernetes dashboard backend源码剖析

    dashboard架构主要由一个API handler 和 五个manager构成: API handler用来处理来自客户的http请求,不同的path路由到不同的的handler处理,使用的是go ...