结对项目
| 这个作业属于哪个课程 | 课程 |
| ---- | ---- | ---- |
| 这个作业要求在哪里 | 要求 |
| 这个作业的目标 | 实现四则运算生成器+结对开发 |
| 项目成员 | 3119005413何子阳 github |
| 项目成员 | 3119005414黄浩 github |
github链接
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 40 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 40 |
Development | 开发 | 720 | 835 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 80 |
· Design Spec | · 生成设计文档 | 40 | 50 |
· Design Review | · 设计复审 | 20 | 40 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 60 | 70 |
· Coding | · 具体编码 | 240 | 300 |
· Code Review | · 代码复审 | 40 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 240 | 215 |
Reporting | 报告 | 65 | 70 |
· Test Report | · 测试报告 | 20 | 25 |
· Size Measurement | · 计算工作量 | 15 | 15 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 815 | 945 |
一、效能分析
JProfiler性能分析图
内存使用情况
在执行过程中,内存消耗较大的是检测式子是否重复功能,我们将一个式子的元素(运算数,运算符)放入一个set中进行过滤;分析发现当运算符数量大于2时,重复的概率非常小,因此只对运算符数量为1和2的式子进行重复检测,提升了效率。
二、设计实现过程
项目结构
项目类图
类功能说明
- Preparement:准备工作类,包含运算数的生成和大小比较,简单运算式的计算
- simpleFormulaGenerator:简单运算器生成器,生成运算符数量1的运算式
- ComplexFormulaGenerator:复杂运算器生成器,生成运算符数量大于1的运算式
- FileGenerator:生成题目和答案文件
- Compare:将答案文件和用户提交的文件进行比对,统计正确率
- FileGenerator:生成批改文件
三、代码说明
complicatedGenerate:利用简单表达式生成复杂表达式,不满足条件的表达式舍弃、返回空值,细节处已用注释表明
public static AnswerV2 complicatedGenerate(){
GenerateHelper g = new GenerateHelper();
char mark = markSet[g.getMarkType()];
//生成第一个数,随机决定生成数字或简单表达式
if(g.getFirstType() == 0){
String firstNum = fractionGenerator();
g.expression.append(firstNum);
g.setFirstRes(firstNum);
}
else{
AnswerV2 result = GenerateV2();
while (result==null){
result = GenerateV2();
}
//获取符号进行加括号的判断
g.setFirstMark(result.getMark());
g.setSecMark(mark);
g.setFirstRes(result.getResult());
//加括号的情况:前一表达式为加减而后一表达式为乘除
if((g.getFirstMark() == '+' || g.getFirstMark() == '-') && (g.getSecMark() == 'x' || g.getSecMark() == '÷'))
g.expression.append('(').append(result.getExpression()).append(')');
else g.expression.append(result.getExpression());
}
g.expression.append(" "+mark+" ");
if(g.getFirstMark()!='0') g.setFirstMark(mark);
else g.setSecMark(mark);
//生成第二个数
if(g.getSecType() == 0){
String secNum = fractionGenerator();
g.expression.append(secNum);
g.setSecRes(secNum);
}
else{
AnswerV2 result = GenerateV2();
while (result==null){
result = GenerateV2();
}
if(g.getSecMark()=='0') g.setSecMark(result.getMark());
else g.setThrMark(result.getMark());
g.setSecRes(result.getResult());
//加括号的情况:前一表达式为加减而后一表达式为乘除
//或前除后乘
if(((g.getThrMark() == '+' || g.getThrMark() == '-') && (g.getSecMark() == 'x' || g.getSecMark() == '÷'))||
(g.getThrMark()=='x'&&g.getSecMark()=='÷')
)
g.expression.append('(').append(result.getExpression()).append(')');
else g.expression.append(result.getExpression());
}
/*总体答案是负数或除数为0则舍弃*/
if(mark=='-' && !fractionComparator(g.getFirstRes(),g.getSecRes())) return null;
else if(mark=='÷' && g.getSecRes().equals("0")) return null;
//对单双运算符的运算式子进行重复审计
if(g.getFirstType()+g.getSecType()<2){
Set<String> newSet = new HashSet();
newSet.add(g.getFirstRes());
newSet.add(g.getSecRes());
newSet.add(mark+"");
if(expressionComparator.contains(newSet)) return null;
else expressionComparator.add(newSet);
}
g.setFinalRes(fractionCalculator(g.getFirstRes(),g.getSecRes(),g.getMarkType()));
return new AnswerV2(g.expression.toString(),g.getFinalRes(),'0');
}
fractionCalculator:计算真分数或整数计算的结果
public static String fractionCalculator(String firstNum, String secNum, int markType) {
String s = "";
String[] fir = fractionToArray(firstNum);
String[] sec = fractionToArray(secNum);
switch (markSet[markType]) {
case '+':
s = fractionAddition(fir, sec);
break;
case '-':
s = fractionSubtraction(fir, sec);
break;
case 'x':
s = fractionMultiplication(fir, sec);
break;
case '÷':
s = fractionDivision(fir, sec);
break;
}
return s;
}
四、测试运行
整体运行结果
-
主界面
-
批改界面
-
生成文件目录:D盘根目录下
-
生成结果
要求3:生成的题目中计算过程不能产生负数
在生成表达式时进行了值的比较,将结果为负数的式子舍弃
要求4:生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数
自行设计了一个分数约分的方法,保证分数都是最简形式或真分数
要求5:每道题目中出现的运算符个数不超过3个
算式生成采用了子表达式组装的形式,若复杂表达式两个操作数都是子表达式则整个表达式含3个运算符;若两个操作数都是数字则表达式含1个运算符;
要求6:不会产生重复的表达式
维护了大一个HashSet用来储存过程中产生的所有表达式,通过HashSet的特性保证表达式不会重复
要求7:生成的题目存入执行程序的当前目录下的Exercises.txt文件,在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
已满足,在整体情况已展示
要求8:程序应能支持一万道题目的生成
要求9:程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计
单元测试
进行10000道题目的生成,没有问题
五、项目小结
成员1:何子阳
1.这是一次很有收获的项目体验。本次作业的题目容易理解,但实现起来有很多方面需要考虑,各个方面综合在一起之后有一种很大的制约的感觉,终于也是完成了这个项目;
2.在这次项目之中也第一次体验到合作开发,我们将项目按功能分为了几个部分并分配到每个人完成,需要用到对方的功能则调用接口,因此在接口设计上也有了一个新的认识。
成员2:黄浩
本次项目是有我和何子阳同学共同完成的,这次的合作项目中,很感谢队友的帮助,感受到了合作的的重要性,我们从一开始的讨论到分工合作都进行的很顺利,合作的过程不断综合各自的想法进行完善,最终完成了这个项目。