【软件工程】小学四则运算 “软件”之初版
作业要求来源于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2186
我的github远程仓库的地址: https://github.com/RichardSkr/Simple-arithmetic-device
一、实验要求
像《构建之法》的人物阿超那样,写一个能自动生成小学四则运算题目的命令行 “软件”。
具体要求:任何编程语言都可以,命令行程序接受一个数字输入,然后输出相应数目的四则运算题目和答案。例如输入数字是 30, 那就输出 30 道题目和答案。 运算式子必须至少有两个运算符,运算数字是在 100 之内的正整数,答案不能是负数。 如:
23 - 3 * 4 = 11
扩展要求:
1) 要求能出和真分数 (二分之一, 十二分之五,等)相关的练习题。
2) 并且要求能处理用户的输入,并判断对错,打分统计。 要求能处理用户输入的真分数, 如 1/2, 5/12 等。
初步拟定要实现的功能后,估计一下自己需要花多长时间。编程过程中记录自己实际用了多长时间。
然后和同学们比较一下各自程序的功能、实现方法的异同等等。
写博客纪录自己实现的过程和思路。
二、功能模块
1、模块设计:
(1)MainWork:主类,用于获取用户输入数据、输出获取的题目列表和答题情况
(2)ExerciseUtils:练习题工具类,用于生成题目列表
(3)ExerciseBean:练习题对象类,用于存储该题目的运算数、运算符和答案
2、数据结构:
(1)ExerciseBean对象类中,用整型数组存储自动生成的运算数,用字符串数组存储自动生成的运算符;
public int[] num; //运算数 public String[] operator; //运算符 public int degree = 3; //难度 public int answer = 0; //答案
(2)主类中采用了List对象集合将储存练习题列表;
List<ExerciseBean> exerciseList = ExerciseUtils.getExerciseList(exerciseCount);
3、算法:
(1)随机生成运算数和运算符
for (int i = 0; i < degree; i++) { this.num[i] = rand.nextInt(100); int oper = rand.nextInt(4); if (i == degree - 1) { this.operator[degree - 1] = "="; } else { switch (oper) { case 0: this.operator[i] = "+"; break; case 1: this.operator[i] = "-"; break; case 2: this.operator[i] = "*"; break; case 3: this.operator[i] = "/"; break; } } }
(2)生成题目列表集合
for (int i = 0; i < exerciseCount; i++) { exerciseList.add(new ExerciseBean()); }
(3)输出题目
for (int j = 0;j < 3;j++){ exercise += exerciseList.get(i).num[j] + exerciseList.get(i).operator[j]; } System.out.print(exercise);
(4)判断运算顺序,先进行乘除运算,再进行加减运算,遍历运算符集合,通过用answer变量计算某运算符前后的数据,运算完后使当前运算符出栈,并把运算符前的数据替换成运算结果,运算符后的数据出栈;除法运算用变量numerator和denominator记录分子和分母,使分子参与运算,分母在运算符优先级的运算完后再参与运算这里只列出部分代码,完整代码请参考ExerciseBean对象类中的getAnswer()方法。
for (int i = 0; i < answer_operator.size(); ){ //先乘除 if (answer_operator.get(i).equals("*")){ answer = answer_num.get(i) * answer_num.get(i+1); answer_num.set(i,answer); answer_num.remove(i+1); answer_operator.remove(i); }else if (answer_operator.get(i).equals("/")){ numerator = answer_num.get(i); answer = numerator; denominator = answer_num.get(i+1) * denominator; answer_num.set(i,numerator); numerator_index = i; answer_num.remove(i+1); answer_operator.remove(i); }else i++;
}
三:主要代码
(1)MainWork
1 import java.util.List; 2 import java.util.Scanner; 3 4 public class MainWork { 5 public static void main(String arg[]){ 6 Scanner in =new Scanner(System.in); 7 System.out.print("请输入出题数:"); 8 int exerciseCount=in.nextInt(); 9 String answer;//用户输入的答案 10 System.out.println("共有"+ exerciseCount + "题"); 11 List<ExerciseBean> exerciseList = ExerciseUtils.getExerciseList(exerciseCount); 12 int score = 0; //用户答题得分 13 for (int i = 0;i<exerciseList.size();i++){ 14 String exercise = i+1 + "、"; 15 for (int j = 0;j < 3;j++){ 16 exercise += exerciseList.get(i).num[j] + exerciseList.get(i).operator[j]; 17 } 18 System.out.print(exercise); 19 answer = in.next(); 20 if (answer.equals(exerciseList.get(i).getAnswer())){ 21 //System.out.println("答案"+exerciseList.get(i).getAnswer()); 22 score++; 23 System.out.println("答对了,很优秀!"); 24 }else { 25 System.out.println("答错了,真遗憾!"); 26 System.out.println("正确答案是"+exerciseList.get(i).getAnswer()); 27 } 28 } 29 System.out.println("答题结束!总成绩为"+score*100/exerciseCount+"分"); 30 } 31 }
(2)ExerciseBean对象类
1 import java.util.*; 2 3 public class ExerciseBean { 4 public int[] num; //运算数 5 public String[] operator; //运算符 6 public int degree = 3; //难度 7 public int answer = 0; //答案 8 public ExerciseBean(){ 9 do { 10 createExercise(); 11 }while (answer < 0); 12 } 13 14 /** 15 * 习题初始化 16 */ 17 private void createExercise(){ 18 Random rand =new Random(); 19 this.num = new int[degree]; 20 this.operator = new String[degree]; 21 for (int i = 0; i < degree; i++) { 22 this.num[i] = rand.nextInt(100); 23 int oper = rand.nextInt(4); 24 if (i == degree - 1) { 25 this.operator[degree - 1] = "="; 26 } else { 27 switch (oper) { 28 case 0: 29 this.operator[i] = "+"; 30 break; 31 case 1: 32 this.operator[i] = "-"; 33 break; 34 case 2: 35 this.operator[i] = "*"; 36 break; 37 case 3: 38 this.operator[i] = "/"; 39 break; 40 } 41 } 42 } 43 } 44 45 /** 46 * 计算算式答案 47 * 返回答案字符串 48 */ 49 public String getAnswer(){ 50 int answer = 0; 51 int denominator = 1;//分母 52 int numerator = 1; //分子 53 int numerator_index = -1; //分子坐标 54 List<Integer> answer_num = new ArrayList<Integer>(); 55 List<String> answer_operator = new ArrayList<String>(); 56 for (int i = 0;i < num.length;i++){ 57 answer_num.add(num[i]); 58 answer_operator.add(operator[i]); 59 } 60 for (int i = 0; i < answer_operator.size(); ){ //先乘除 61 if (answer_operator.get(i).equals("*")){ 62 answer = answer_num.get(i) * answer_num.get(i+1); 63 answer_num.set(i,answer); 64 answer_num.remove(i+1); 65 answer_operator.remove(i); 66 }else if (answer_operator.get(i).equals("/")){ 67 numerator = answer_num.get(i); 68 answer = numerator; 69 denominator = answer_num.get(i+1) * denominator; 70 answer_num.set(i,numerator); 71 numerator_index = i; 72 answer_num.remove(i+1); 73 answer_operator.remove(i); 74 }else 75 i++; 76 } 77 for (int i = 0; i < answer_operator.size(); ){ //后加减 78 if (answer_operator.get(i).equals("+")){ 79 if (i == numerator_index){ 80 answer_num.set(i+1,answer_num.get(i+1) * denominator); 81 }else if ((i+1) == numerator_index){ 82 answer_num.set(i,answer_num.get(i) * denominator); 83 } 84 answer = answer_num.get(i) + answer_num.get(i+1); 85 answer_num.set(i,answer); 86 answer_num.remove(i+1); 87 answer_operator.remove(i); 88 }else if (answer_operator.get(i).equals("-")){ 89 if (i == numerator_index){ 90 answer_num.set(i+1,answer_num.get(i+1) * denominator); 91 }else if ((i+1) == numerator_index){ 92 answer_num.set(i,answer_num.get(i) * denominator); 93 } 94 answer = answer_num.get(i) - answer_num.get(i+1); 95 answer_num.set(i,answer); 96 answer_num.remove(i+1); 97 answer_operator.remove(i); 98 }else 99 i++; 100 } 101 this.answer = answer/denominator; 102 if (denominator != 1){ 103 int gongyinshu = 1; 104 int smaller = answer > denominator ? denominator : answer; 105 for (int i = 1; i <= smaller; i++) { 106 if (answer % i == 0 && denominator % i == 0) { 107 gongyinshu = i; 108 } 109 } 110 answer = answer / gongyinshu; 111 denominator = denominator / gongyinshu; 112 return answer + "/" + denominator; 113 }else 114 return answer+""; 115 } 116 117 //设置题目难度 118 private void setDegree(int degree){ 119 this.degree = degree; 120 } 121 122 }
(3)ExerciseUtils工具类
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class ExerciseUtils { 5 public static List<ExerciseBean> getExerciseList(int exerciseCount) { 6 List<ExerciseBean> exerciseList = new ArrayList<ExerciseBean>(); 7 for (int i = 0; i < exerciseCount; i++) { 8 exerciseList.add(new ExerciseBean()); 9 } 10 return exerciseList; 11 } 12 }
四、运行结果
五:时间表
PSP2.1 | Personal Software Process Stages | Time Senior Student | Time |
Planning | 计划 | 20 | 15 |
.Estimate | 估计这个任务需要多少时间 | 20 | 15 |
Development | 开发 | 120 | 150 |
.Analysis | 需求分析 (包括学习新技术) | 20 | 15 |
.Design Spec | 生成设计文档 | 0 | 0 |
.Design Review | 设计复审 | 5 | 10 |
.Coding Standard | 代码规范 | 10 | 10 |
.Design | 具体设计 | 20 | 15 |
.Coding | 具体编码 | 35 | 70 |
.Code Review | 代码复审 | 10 | 5 |
.Test | 测试(自我测试,修改代码,提交修改) | 20 | 25 |
Reporting | 报告 | 9 | 6 |
· | 测试报告 | 4 | 4 |
· | 计算工作量 | 5 | 2 |
· | 并提出过程改进计划 | 0 | 0 |
六、遇到的问题及如何解决
(1)问题:在设计运算符优先级时,优先级相同的运算符只有出现一次时只运算一次,比如a*b+c可以运算正确因为“*”和“+”优先级不一样,而a*b/c就只能进行一次运算符的运算。
解决方法:经过测试之后发现是由于在for循环里面,运算完的运算符出栈了,但是下标i进行了++操作,导致不能获取到运算符集合里的下一个运算符,所以在改为在没有这一优先级的运算符时才进行下标++操作。
(2)问题:进行除法运算时,使用"/"运算符只能得到整型数据而不能得到真分数。
解决方法:定义两个变量分别存储分子和分母的值,分母初始化为1,在进行除法运算时,记录分子下标,并为分子和分母赋值,进行加减法运算时判断运算符前后是否有存储分子的数据,有的话则使另一个运算数与分母相乘,在进行优先级运算后,当分母不为1是,把结果和分母进行约分并用字符串组合起来,得到最终结果。