仓库地址:https://git.coding.net/DandelionClaw/CalculateProject.git
1.需求分析:
Ⅰ程序可接收一个输入参数n,然后随机产生n道加减乘除(分别使用符号+-*÷来表示)练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间。
Ⅱ每个练习题至少要包含2种运算符。不能存在分数、负数与非整数。
2.功能设计:
①基本功能:
Ⅰ 在用户输入错误数据时提示
Ⅱ 自动随机生成用户输入个数的算式,并给出算式答案
Ⅲ 将结果生成为文件,如果存储错误会提示
②扩展功能
Ⅰ 考虑到小学生计算水平,将算式结果约束在0~100间
Ⅱ 随机产生括号并保证算式正确性
Ⅲ 在用户输入的算式数中,一半是(随机)带括号的普通四则运算算式,一半是分数算式
3.设计实现:
定义了算式“Formula”类,用于定义算式和定义静态变量加减乘除,createString()方法用于生成算式字符串,setOps()方法用于生成算式类的每个操作符,setAns()方法用于计算每个算式的结果。
定义了分数算式“Fraction”类,它继承了Formula类,并扩展出了getFraction()方法用于生成分式,gcd()方法用于计算两数最大公因数。
在普通的四则运算中createFormula()函数用于生成算式。
在分数四则运算中createFormulaWithFraction()函数用于生成算式。
createFile()函数用于生成文件。
关系如下图所示
4.算法详解:
对于生成题目,我用到了随机函数库Random,先随机生成操作符,再随机生成参数,通过判断操作符是否是除法和减法再调整参数。
对于生成答案,我的第一反应是利用算法通过堆栈实现,但是我脑海中突然浮现出另一个想法。在寒假自学的Python中有一个函数eval()可以把字符串转换成表达式,这个方法刚好适用于此时的情形。虽然Java没有eval函数,但是JavaScript有。Python和JavaScript都是脚本函数,只要使用ScriptEngine调用js脚本即可调用eval函数。我先设计了getString()函数得到每个算式的字符串表达,然后通过上述方法轻松实现字符串到算术的转换。
对于求最大公因数,我使用了运用辗转相除法的递归方法求得。
对于括号的添加,我先设定一个参数isbracket,用随机函数生成其值,若为1则该算式含括号,若为0则不含。含括号时,我再使用随机函数产生上括号所在位置,然后再计算出下括号位置,添加在字符串中。
5.测试运行:
6.代码展示:
public void setAns() throws ScriptException//算术表达式结果计算函数 { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine se = manager.getEngineByName("js"); this.ans = (Integer) se.eval(this.str); }
1 public void setOps() {//随机生成操作符函数 2 Random r = new Random(); 3 for(int i=1;i<=this.num_of_operation;i++){ 4 this.ops[i] = r.nextInt(4); 5 if(this.ops[i]==3&&this.ops[i-1]==3){ 6 this.ops[i-1]=r.nextInt(2); 7 } 8 } 9 //排除符号单一情况 10 boolean flag = true; 11 for(int i=2;i<=this.num_of_operation;i++){ 12 if(this.ops[i]!=this.ops[i-1]){ 13 flag = false; 14 } 15 } 16 if(flag){ 17 do{ 18 this.ops[2] = r.nextInt(3); 19 } 20 while(this.ops[2]==this.ops[1]); 21 } 22 }
public int gcd(int x, int y){ //求最大公约数 if(y == 0) return x; else return gcd(y,x%y); }
7.总结:
对于软件模块化,我将程序的每个功能都单独作为函数独立出来,实现了可复用性和可维护性。先列出各功能(函数)的关系,形成结构框架,然后自顶向下设计,逐步求精,完成各函数的编写。
8.PSP展示:
任务内容 |
计划共完成需要的时间(min) |
实际完成需要的时间(min) |
计划 |
10 |
8 |
· 估计这个任务需要多少时间,并规划大致工作步骤 |
10 |
8 |
开发 |
246 |
326 |
· 需求分析 (包括学习新技术) |
6 |
10 |
· 生成设计文档 |
5 |
5 |
· 设计复审 (和同事审核设计文档) |
5 |
6 |
· 代码规范 (为目前的开发制定合适的规范) |
5 |
3 |
· 具体设计 |
10 |
12 |
· 具体编码 |
180 |
203 |
· 代码复审 |
5 |
9 |
· 测试(自我测试,修改代码,提交修改) |
30 |
78 |
报告 |
10 |
9 |
· 测试报告 |
3 |
2 |
· 计算工作量 |
2 |
1 |
· 事后总结, 并提出过程改进计划 |
5 |
6 |
我在具体编码时间和测试时间两栏远远超过了计划。
原因是在具体编码时我低估了算法的复杂性,在乘法方面可能会导致算式结果过大,因在这方面调整算法。
在测试时,出现了一个bug,经排查,是在保证计算无小数时,我使用调整算式参数的方法,但我在调整参数之前就已经把参数输入字符串,导致最后的结果仍是未经更改有小数的。之后又花了大量的时间反复修改,精简代码。