一、题目描述:

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. Direcshow中视频捕捉和参数设置报告

    Direcshow中视频捕捉和参数设置报告 1.      关于视频捕捉(About Video Capture in Dshow) 1视频捕捉Graph的构建 一个能够捕捉音频或者视频的graph图 ...

  2. Flex动态获取数据,服务中断报错

    1.错误原因 2.错误原因 由上面提示可知,软件引起的链接中断,导致出错 3.解决办法 检查数据库链接,重新启动服务

  3. PageBase 公共基础类

    PageBase 公共基础类 using System; using System.Collections.Generic; using System.Linq; using System.Web; ...

  4. hdu5788 level up

    贴下以前写的代码 比赛前我准备着重看的 主席树 树dp 字符串 #include<bits/stdc++.h> using namespace std; typedef long long ...

  5. zk个人入门学习总结(1)

    ZooKeeper是一种分布式协调服务,用于管理大型主机.在分布式环境中协调和管理服务是一个复杂的过程.ZooKeeper通过其简单的架构和API解决了这个问题.ZooKeeper允许开发人员专注于核 ...

  6. mybatis快速入门(六)

    前面mybatis的入门程序基本上都写完了,就看大家的灵活运用了,今天来吧前面的整合一下封装一个公共的BaseDao 只需要把前面的改造下然后创建一个BaseDao的接口,其它的继承BaseDao接口 ...

  7. 使用非直接缓冲区与直接缓冲区进行文件的复制(基于Channel)

    一.利用通道完成文件的复制(非直接缓冲区)     long start = System.currentTimeMillis(); FileInputStream fis = new FileInp ...

  8. wcf类库及宿主

    说起wcf,一直以来总是直接创建wpf的应用程序,这样默认的宿主是IIS.如果想更换宿主,那么我们首先得创建wcf类库. 这个类库会自动创建一个app.config文件.到最后部署的时候,把它移到宿主 ...

  9. ImageButton 图像按钮

    ImageButton 类主要成员有: setINMask 属性: 数据类型:Bool, {get ,set}. 用于确定是否接受用户输入操作,它的值是传给一个指针.这个指针指向的当前图像按钮所在的窗 ...

  10. SparkHiveContext和直接Spark读取hdfs上文件然后再分析效果区别

    最近用spark在集群上验证一个算法的问题,数据量大概是一天P级的,使用hiveContext查询之后再调用算法进行读取效果很慢,大概需要二十多个小时,一个查询将近半个小时,代码大概如下: try: ...