软件工程 | 网工1934-软件工程 (广东工业大学 - 计算机学院) |
---|---|
作业要求 | 实现一个自动生成小学四则运算题目的命令行程序 |
作业目标 | 1.使用 -n 参数控制生成题目的个数。 2.使用 -r 参数控制题目中数值的范围。 3.生成的题目中计算过程不能产生负数。 4.生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。 5.每道题目中出现的运算符个数不超过3个。 6.程序一次运行生成的题目不能重复。 7.在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件。 8.程序应能支持一万道题目的生成。 9.程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。 |
队员:3119005390欧振浩
GitHub 链接
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | 740 | 1110 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 240 | 360 |
· Design Spec | · 生成设计文档 | 40 | 30 |
· Design Review | · 设计复审 | 10 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 60 | 50 |
· Coding | · 具体编码 | 180 | 240 |
· Code Review | · 代码复审 | 60 | 100 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | ||
· Test Report | · 测试报告 | 30 | 40 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 740 | 1110 |
二、效能分析
三、设计实现过程
共使用了四个类
homework 类
是main方法所在的类,可调用其他类的静态方法实现需求
calculator 类
计算加减乘除以及返回答案的类
reductionofFraction 类
将输入的两个数进行约分的类
change 类
将假分数化为带分数的类
各类之间关系
四、代码说明
homework 类
import java.io.*;
import java.util.*;
public class homework {
private static Random random = new Random();
public static int range;
public static void main(String[] args) {
// 依次转化为字符串,设置题目
System.out.println("请输入“ -r 数字”或“-r 数字 -n 数字”");
if(args[0]!="-r") {
System.out.println("请输入“ -r 数字”或“-r 数字 -n 数字”");
}
else {
range = Integer.parseInt (args[1]);
}
int num;
if(args[2]=="-n") {
num = Integer.parseInt (args[3]);
}
else {
num = 10000;
}
//int num=10,range=10;
for(int j=0;j<num;j++) {
int a[] = new int[6];
for (int i = 0; i < 6; i++) {
a[i] = random.nextInt(range);
}//创建随机数
int b[] = new int[2];//创建随机运算符
b[0] = random.nextInt(4);
b[1] = random.nextInt(5);//可能不存在第二个运算符
b[1] = 4;//技术有限先不考虑第二个运算符
int c[] = new int[6];//计算
if (b[1] == 4) {
c = calculator.main(a[1], a[2], a[3], a[4], b[0]);
}
if(c[5]!=-1) {//若答案的除数非0才会进入
String exercises[] = new String[1];//构建题目
exercises[0] = reductionofFraction.main(c[0], c[1]);
switch (b[0]) {
case 0: {
exercises[0] += " + ";
break;
}
case 1: {
exercises[0] += " - ";
break;
}
case 2: {
exercises[0] += " × ";
break;
}
case 3: {
exercises[0] += " ÷ ";
break;
}
}
exercises[0] += reductionofFraction.main(c[2], c[3]);
exercises[0] += " =";
String answer[] = new String[1];//计算答案
answer[0] = reductionofFraction.main(c[4], c[5]);
FileWriter fExercises = null;
try {
File f = new File("Exercises.txt");//题目写入
fExercises = new FileWriter(f, true);
} catch (IOException e) {
e.printStackTrace();
}
if (exercises[0] != null) {
PrintWriter pExercises = new PrintWriter(fExercises);
pExercises.println(j + 1 + "." + exercises[0]);
pExercises.flush();
try {
fExercises.flush();
pExercises.close();
fExercises.close();
} catch (IOException e) {
e.printStackTrace();
}
}
FileWriter fAnswer = null;
try {
File f = new File("Answer.txt");//答案写入
fAnswer = new FileWriter(f, true);
} catch (IOException e) {
e.printStackTrace();
}
if (exercises != null) {
PrintWriter pAnswer = new PrintWriter(fAnswer);
pAnswer.println(j + 1 + "." + answer[0]);
pAnswer.flush();
try {
fAnswer.flush();
pAnswer.close();
fAnswer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
else j--;//否则此次随机过程作废
}
// 退出程序
System.exit(0);
}
}
calculator 类
public class calculator {
public static int[] main(int a, int b,int c,int d,int x) {
int numerator=0,denominator = 0;
int answer[]=new int[6];
if(b!=0&&d!=0) {//判定分母是否有0
}
else{//若有零则将分母置1
b=1;d=1;
}
switch (x) {
case 0: {//加
numerator = a * d + b * c;
denominator = b * d;
break;
}
case 1: {//减
if ((a * d - b * c) < 0) {//若出现负数则减数与被减数互换
int xx=a;
a=c;
c=xx;
xx=b;
b=d;
d=xx;
}
numerator = a * d - b * c;
denominator = b * d;
break;
}
case 2: {//乘
numerator = a * c;
denominator = b * d;
break;
}
case 3: {//除
numerator = a * d;
denominator = b * c;//c有概率为0,导致报错
break;
}
}
answer[0]=a;
answer[1]=b;
answer[2]=c;
answer[3]=d;
answer[4]=numerator;
if (denominator!=0) {//判定答案的除数是不是0,若是,则返回-1,此次报废
answer[5] = denominator;
}
else{
answer[5] = -1;
}
return answer;
}
}
reductionofFraction 类
public class reductionofFraction {
public static int gcd(int m,int n)//辗转相除法求最大公约数
{ if(n == 0){
return m;
}
int r = m%n;
return gcd(n,r);
}
public static String main(int a, int b) {// 分数约分,用于计算结果
int i = gcd(a,b);
int x = a / i;// 分子
int y = b / i;// 分母
if (x == 0) {
return "0";
}
//if(y==0) return "y=0";曾用于测试哪里使程序报错
if(y==1) return x+"";
else return change.main(x,y);
}
}
change 类
public class change {
public static String main(int a, int b) {//判断假分数,并化假分数为带分数
if(a>=b) {
int c;
c=a/b;
int d;
d=a%b;
{
if(d==0) {
return c+"";//若两数可以整除
}
return c+"'"+d+"/"+b;//分子大于分母可以转化为带分数
}
}return a+"/"+b;//分子小于分母不能转化为带分数
}
}
五、测试运行
可以生成10道,当不指定题目数量时默认生成10000道
六、项目小结
起初想做出两个及以上运算符的四则运算,但是一旦引入括号后问题感觉复杂了很多,在网上查到了可以使用逆波兰式解决这个问题,但因为自己使用的计算答案的过程有将题目里的子表达式做改变,想了很久也没有想到如何在这个方法里插入逆波兰式。
而且时间匆忙,打分功能也还没来得及做。但是在查阅资料的过程中收获良多。