一、项目Github地址
https://github.com/Transform21/Calculator
二、项目报告
1、需求分析
(1)程序可接收一个输入参数n,然后随机产生n道加减乘除练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间,即运算数字在4~6个之间。
(2)为了让小学生得到充分锻炼,每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3/5+2=2.6,2-5+10=7等算式。
(3)练习题生成好后,自己的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中,不要输出额外信息,文件目录与程序目录一致。
(4)当程序接收的参数为5时,即产生5个运算式。
2、功能设计
(1)、输入所需要生成式子的个数。
(2)、为了让小学生得到充分锻炼,每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3/5+2=2.6,2-5+10=7等算式。
(3)、练习题生成好后,将自己的学号
(4)、当程序接收的参数为4时,以下为输出文件示例。
5、计算出表达式的结果,并且运算过程中不能出现负数。
6、最后将运算表达式和计算结果写入result.txt文件。
3、设计实现
首先,要随机产生运算式自然少不了随机数的定义,生成随机数的重要函数即Math.random,举个例子,要生成n个数字组成的运算式,需要n-1个字符,运算数随机从1-100中生成,运算符则随机从‘+’‘-’‘*’‘/’四个运算符号中产生,generateRandomNum()定义产生随机数的函数,最终将所产生的随机式按照规定格式输出。同时,既然是小学生运算,不能出现负数,那么在运算函数compute()中要设定运算规定,当计算所得值为负时,程序自动跳出重新产生随机数,直到所产生值为正将运算符输出。在定义除法运算时,除了避免负数的产生,同时还要排除除数等于0的情况,同样方式,在产生随机数为负数或0时,continue跳出循环重新执行程序产生随机数。最后writeToFile()是定义将最终正确结果同步到文件中的情况。
4、测试运行
’单击右键在"git bash here"中运行Main.java文件,输入产生运算式个数number为4时,生成如下运算式并同时生成result.txt文件,如下图所示:
5、展示PSP
PSP2.1 |
任务内容 |
计划完成的时间(min) |
实际完成需要的时间(min) |
PLanning |
计划 |
30 |
30 |
Estimate |
估计这个任务需要多少时间,并规划大致工作步骤 |
30 |
30 |
Developmet |
开发 |
360 |
420 |
Analysis |
需求分析(包括学习新技术) |
120 |
120 |
Design Spec |
生成设计文档 |
15 |
15 |
Design Revie |
设计复审(和同事审核设计文档) |
10 |
10 |
Coding Standard |
代码规范 |
25 |
25 |
Design |
具体设计 |
20 |
30 |
Coding |
具体编码 |
120 |
240 |
Code Review |
代码复审 |
10 |
10 |
Test |
测试(自我测试,修改代码,提交修改) |
20 |
30 |
Reporting |
报告 |
30 |
30 |
Test Report |
测试报告 |
20 |
20 |
Size Measurement |
计算工作量 |
10 |
10 |
Postmortem & Process Improvement Plan |
事后总结,并提出过程改机计划 |
10 |
15 |
6、核心代码
(1)产生随机数的过程。
public static int generateRandomNum(int min, int max) { Random random = new Random(); return random.nextInt(max - min + 1) + min; }
(2)四则运算法则结果的限制,如结果不能为负。
18 try { 19 if (secondOperator.equals(MUL) || secondOperator.equals(DIV)) { 21 int Result = yunsuan(sNum, tNum, secondOperator); 22 if (preResult < 0) { 23 continue; 24 } 25 result = yunsuan(fNum, Result, firstOperator); 26 } else { 27 int Result = yunsuan(fNum, sNum, firstOperator); 28 if (Result < 0) { 29 continue; 30 } 31 result = yunsuan(Result, tNum, secondOperator); 32 } 33 } catch (Exception e) { 34 35 continue; 36 } 37 38 39 if (result < 0) { 40 continue; 41 } else { 42 43 StringBuffer buffer = new StringBuffer(); 44 45 buffer.append(fNum).append(firstOperator).append(sNum).append(secondOperator).append(tNum) 46 .append("=").append(result).append(" "); 47 48 System.out.println(buffer); 49 50 if (writeToFile(buffer.toString())) { 51 52 return true; 53 54 } else { 55 56 return false; 57
(3)关于运算
public static Integer yunsuan(int firstNum, int secNum, String operator) throws Exception{ switch (operator) { case ADD: { return firstNum + secNum; } case SUB: { return firstNum - secNum; } case MUL: { return firstNum * secNum; } case DIV: { if (firstNum % secNum == 0) { return firstNum / secNum; } else { throw new Exception(""); } } default: { return null; }
7、总结
关于模块化的设定在设计分析时已有提到,框架比较简单,主函数中设定参数,参数值不同最终产生的计算式个数不同。总体来说程序花费较长时间,由于我的疏忽,之前写好的代码不慎丢失,当电脑强制关机后打开看到之前做的工作没有保存时内心真的很绝望,但最终却还是要静下心来将项目一步步完成,最终在同学的帮助下才勉强将代码完成快快上交。关于附加功能中的括号问题,在之前的代码中有尝试加入,关于优先级的问题一开始只想简单的用来栈解决,但是在处理‘+’‘-’‘*’‘/’的优先级还好,遇到括号就不知道怎么处理了。最后搜了一下网上的内容发现将栈和逆波兰式结合解决这个问题会是更好的解决办法,于是尝试加入了一下,最终没有成功,终归还是写的代码太少,功底太弱.加之作业截止时间已到,于是仓促之下将代码和博客提交.在后期时间允许的情况下,还是想尝试着将所有附加功能再试着实现一次,更新到博客中。