结对项目-自动生成四则运算题目

GitHub项目地址:https://github.com/LixinXie/WorkTogetherProject

结对成员:18软3谢立新(3118005071)、18软3高山(3118005048)

正文

一、项目需求

  1. 使用 -n 参数控制生成题目的个数,例如

    Myapp.exe -n 10  将生成10个题目。

  1. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如

    Myapp.exe -r 10

    将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。

  1. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。
  2. 生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。
  3. 每道题目中出现的运算符个数不超过3个。
  4. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。

    生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下: 

    1. 四则运算题目1
    2. 四则运算题目2
    3. ……

    其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

  1. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
    1. 答案1
    2. 答案2

     特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

  1. 程序应能支持一万道题目的生成。
  2. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:

     Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt

     统计结果输出到文件Grade.txt,格式如下:

      Correct: 5 (1, 3, 5, 7, 9)

      Wrong: 5 (2, 4, 6, 8, 10)

扫描二维码关注公众号,回复: 10345436 查看本文章

     其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

二、设计实现过程

   最初分析设计    

   后来边做边改进的设计

  项目结构

  

三、代码说明

 主函数,进行菜单选择。嵌入了一些记录运行时间的语句(暂时还不会AOP所以使用的传统方法)

 1 public static void main(String[] args) throws Exception {
 2         int n;//题目个数
 3         int r;//数值取值范围
 4         System.out.println("欢迎使用四则运算");
 5         System.out.println("输入 -q 生成题目和答案");
 6         System.out.println("输入 -c 验证你的答案");
 7         System.out.println("-------------------");
 8         System.out.println("请选择你的操作:");
 9         Scanner scanner = new Scanner(System.in);
10         String order = scanner.next();
11         switch(order){
12             case "-q":
13                 System.out.println("题目个数-n (请输入一个正整数):");
14                 n=scanner.nextInt();
15                 System.out.println("数值取值范围-r (请输入一个正整数):");
16                 r=scanner.nextInt();
17                 if(n<0||r<0){
18                     System.out.println("请的输入有误!");
19                     break;
20                 }
21                 long startTime = System.currentTimeMillis(); // 获取开始时间
22                 List<String> questionList = GenerateQuestion.generateQuestion(n,r);
23                 long endTime = System.currentTimeMillis(); // 获取结束时间
24 
25 
26                 long startTime2 = System.currentTimeMillis(); // 获取开始时间
27                 List<String> answerList = Calculator.calculate(questionList);
28                 long endTime2 = System.currentTimeMillis(); // 获取结束时间
29 
30 
31                 long startTime3 = System.currentTimeMillis(); // 获取开始时间
32                 OutputFile.printQuestion(questionList);
33                 long endTime3 = System.currentTimeMillis(); // 获取结束时间
34 
35 
36                 long startTime4 = System.currentTimeMillis(); // 获取开始时间
37                 OutputFile.printAnswer(answerList);
38                 long endTime4 = System.currentTimeMillis(); // 获取结束时间
39 
40                 System.out.println("generateQuestion方法运行时间: " + (endTime - startTime) + "ms");
41                 System.out.println("calculate方法运行时间: " + (endTime2 - startTime2) + "ms");
42                 System.out.println("printQuestion方法运行时间: " + (endTime3 - startTime3) + "ms");
43                 System.out.println("printAnswer方法运行时间: " + (endTime4 - startTime4) + "ms");
44                 break;
45             case "-c":
46                 System.out.println("请输入题目文件:");
47                 Scanner scanner1 = new Scanner(System.in);
48                 String questionfilepath = scanner1.nextLine();
49 
50                 System.out.println("请输入答案文件:");
51                 Scanner scanner2 = new Scanner(System.in);
52                 String answerfilepath = scanner2.nextLine();
53 
54                 List<List> result = CompareAnswer.compareAnswer(questionfilepath,answerfilepath);
55                 OutputFile.printCompareResult(result);
56                 break;
57             default:
58                 System.out.println("你的输入有误!");
59                 break;
60         }
61     }

 生成题目的类,其中包括生成随机符号和随机正整数的方法,各种题目类型的生成方法。生成题目过程中使用了最笨的方法来保证题目计算过程非负

  1 public class GenerateQuestion {
  2 
  3     //生成题目,可被其他类调用
  4     public static List<String> generateQuestion(int n, int r){
  5         List<String> questionList = new ArrayList<>();
  6         Random random = new Random();
  7         for(int i=0;i<n;i++){
  8             int j = random.nextInt(3);
  9             switch (j){
 10                 case 0: questionList.add(oneSymbol(r));
 11                     break;
 12                 case 1: questionList.add(twoSymbol(r));
 13                     break;
 14                 case 2: questionList.add(threeSymbol(r));
 15                     break;
 16             }
 17         }
 18         return questionList;
 19     }
 20     //生成一个随机符号
 21     public static char randomSymbol(){
 22         Character[] s = new Character[4];
 23         Random r= new Random();
 24         int i = r.nextInt(4);
 25         int b;
 26         s[0] = '+';
 27         s[1] = '-';
 28         s[2] = '*';
 29         s[3] = '/';
 30 
 31         return s[i];
 32     }
 33 
 34     //生成一个随机正整数
 35     public static int randomInt(int r){
 36         Random ra = new Random();
 37         int i;
 38         while(true) {
 39             i = ra.nextInt(r);
 40             if(i!=0)break;
 41         }
 42         return i;
 43     }
 44 
 45     //生成一个含一个符号的题目
 46     public static String oneSymbol(int r){
 47         String[] s = new String[2];
 48         int a,b;
 49         char c;
 50         c = randomSymbol();
 51         a = randomInt(r);
 52         b = randomInt(r);
 53         while(c=='-'){//保证计算过程非负
 54             if(a-b>=0){
 55                 break;
 56             }else
 57                 c = randomSymbol();
 58         }
 59         s[1] = a + "" + c + b;
 60         return s[1];
 61     }
 62     //生成一个含两个符号的题目
 63     public static String twoSymbol(int r){
 64         String[] s = new String[2];
 65         int a,b,c;
 66         char c1,c2;
 67         a = randomInt(r);
 68         b = randomInt(r);
 69         c = randomInt(r);
 70         c1 = randomSymbol();
 71         c2 = randomSymbol();
 72         while(c1=='-'||c2=='-'){//保证计算过程非负;当符号为-时判断过程是否产生负数,产生负数则重新生成符号
 73             if(c1=='-'&&c2=='-'){// - -
 74                 if(a-b-c>=0)
 75                     break;
 76             }else if(c1=='-'){// - 其他
 77                 if(c2=='*' && a-(b*c)>=0){// - *
 78                     break;
 79                 }if(c2=='/'&& a*c-b>=0){// - /
 80                     break;
 81                 }
 82                 if(c2=='+'&& a-b>=0)// - +
 83                     break;
 84             }else {// 其他 -
 85                 if(c1=='+' && b-c>=0){// + -
 86                     break;
 87                 }if(c1=='*' && (a*b)-c>=0){// * -
 88                     break;
 89                 }if(c1== '/' && a-b*c>=0){// / -
 90                     break;
 91                 }
 92             }
 93             c1 = randomSymbol();
 94             c2 = randomSymbol();
 95         }
 96         s[1] =""+ a + c1 + b + c2 + c;
 97         return s[1];
 98     }
 99     //生成一个含三个符号的题目
100     public static String threeSymbol(int r){
101         int a=0,b=0,c=0,d=0;
102         String s;
103         String s1,s2;
104         char c1 = randomSymbol();
105         char c2 = randomSymbol();
106         char c3 = randomSymbol();
107         a = randomInt(r);
108         b = randomInt(r);
109         c = randomInt(r);
110         d = randomInt(r);
111         if (c1 == '-' || c2 == '-' || c3 == '-') {
112             while (true) {
113                 if (c1 == '-' && c2 == '-' && c3 == '-') {
114                     if (a - b - c - d >= 0) break;
115                 }
116                 else if (c1=='-'&&c2=='-'){
117                     if(c3=='+' && a-b-c>=0) break;
118                     else if(c3=='*' && a-b-(c*d)>=0)break;
119                     else if(c3=='/' && a*d-b*d-c>=0)break;
120                 }
121                 else if(c1=='-'&&c3=='-') {
122                     if (c2 == '+' && a-b>=0 &&c-d>=0)break;
123                     else if (c2 == '*' && a-(b*c)-d>=0)break;
124                     else if (c2 == '/' && a*c-b-c*d>=0)break;
125                 }
126                 else if(c2=='-'&&c3=='-') {
127                     if (c1 == '+' && b-c-d>=0)break;
128                     else if (c1 == '*' && (a*b)-c-d>=0)break;
129                     else if (c1 == '/' && a-b*c-b*d>=0)break;
130                 }
131                 else if(c1=='-'){
132                     if(c2=='+') {
133                         if(c3=='+' && a-b>=0)break;
134                         else if(c3=='*' && a-b>=0)break;
135                         else if(c3=='/' && a-b>=0)break;
136                     }
137                     else if(c2=='*'){
138                         if(c3=='+' && a-(b*c)>=0)break;
139                         else if(c3=='*' && a-(b*c*d)>=0)break;
140                         else if(c3=='/' && a*d-b*c>=0)break;
141                     }
142                     else if(c2=='/'){
143                         if(c3=='+' && a*c-b>=0)break;
144                         else if(c3=='*' && a*c-b*d>=0)break;
145                         else if(c3=='/' && a*c*d-b>=0)break;
146                     }
147                 }
148                 else if(c2=='-')
149                 {
150                     if(c1=='+') {
151                         if(c3=='+' && b-c>=0)break;
152                         else if(c3=='*' && (b-(c*d))>=0)break;
153                         else if(c3=='/' && b*d-c>=0)break;
154                     }
155                     else if(c1=='*'){
156                         if(c3=='+' && (a*b)-c>=0)break;
157                         else if(c3=='*' && (a*b)-(c*d)>=0)break;
158                         else if(c3=='/' && a*b*d-c>=0)break;
159                     }
160                     else if(c1=='/'){
161                         if(c3=='+' && a-b*c>=0)break;
162                         else if(c3=='*' && a-b*c*d>=0)break;
163                         else if((c3=='/') &&a*d-b*c>=0)break;
164                     }
165                 }
166                 else if(c3=='-')
167                 {
168                     if(c1=='+') {
169                         if(c2=='+' && c-d>=0)break;
170                         else if(c2=='*' && ((b*c)-d)>=0)break;
171                         else if(c2=='/' && b-c*d>=0)break;
172                     }
173                     else if(c1=='*'){
174                         if(c2=='+' && c-d>=0)break;
175                         else if(c2=='*' && (a*b*c-d)>=0)break;
176                         else if(c2=='/' && a*b-c*d>=0)break;
177                     }
178                     else if(c1=='/'){
179                         if(c2=='+' && c-d>=0)break;
180                         else if(c2=='*' && a*c-b*d>=0)break;
181                         else if(c2=='/' && a-b*c*d>=0)break;
182                     }
183                     else continue;
184                 }
185                 c1 = randomSymbol();
186                 c2 = randomSymbol();
187                 c3 = randomSymbol();
188             }
189         }
190         s =""+ a + c1 + b + c2 + c + c3 + d ;
191         return s;
192     }
193 }

计算类,其中有四则运算方法,各种类型题目计算方法。没有使用中缀表达式转后缀表达式进行计算(挺遗憾),因为对后缀表达式不太熟,所以还是用了最笨的方法进行计算

  1 public class Calculator {
  2     public static List<String> calculate(List<String> questionList){//计算题目表达式,题目中没有=和题号
  3         List<String> answerList = new ArrayList<>();
  4         for(int i=0;i<questionList.size();i++){
  5             String str = questionList.get(i);//从list中获取题目
  6             char[] strarray = str.toCharArray();//将当前题目字符串转化为字符数组
  7             int[] sysmbolindex = new int[3];//记录当前题目表达式中按顺序出现的计算符号的索引
  8             char[] sysmbol = new char[3];//记录当前题目表达式中按顺序出现的各个计算符号
  9             int x=0;//x标记当前sysmbolindex数组存放到第几个(索引)
 10             int y=0;//y标记当前sysmbol数组存放到第几个(索引)
 11             int sumsysmbol=0;//记录当前题目运算符个数
 12             for(int j=0;j<strarray.length;j++){//遍历字符数组记录运算符和运算符索引
 13                 if(strarray[j]=='+'||strarray[j]=='-'||strarray[j]=='*'||strarray[j]=='/'){
 14                     sysmbolindex[x]=j;//记录当前运算符的索引
 15                     sysmbol[y]=strarray[j];//记录当前运算符
 16                     if(x<sysmbolindex.length-1)
 17                         x++;//将x向后移动一位
 18                     if(y<sysmbol.length-1)
 19                         y++;//将y向后移动一位
 20                     sumsysmbol++;//运算符个数加一
 21                 }
 22             }
 23             if(sumsysmbol==1){//一运算符题目
 24                 String result = null;
 25                 int num1 = Integer.parseInt(str.substring(0,sysmbolindex[0]));//运算符左边的数
 26                 int num2 = Integer.parseInt(str.substring(sysmbolindex[0]+1));//运算符右边的数
 27                 result = twoNumCalculate(num1,num2,sysmbol[0]);
 28                 answerList.add(result);
 29             }else if(sumsysmbol==2){//二运算符题目
 30                 String result = null;
 31                 int num1 = Integer.parseInt(str.substring(0,sysmbolindex[0]));
 32                 int num2 = Integer.parseInt(str.substring(sysmbolindex[0]+1,sysmbolindex[1]));
 33                 int num3 = Integer.parseInt(str.substring(sysmbolindex[1]+1));
 34                 result = threeNumCalculate(num1,num2,num3,sysmbol[0],sysmbol[1]);
 35                 answerList.add(result);
 36             }else if(sumsysmbol==3){//三运算符题目
 37                 String result = null;
 38                 int num1 = Integer.parseInt(str.substring(0,sysmbolindex[0]));
 39                 int num2 = Integer.parseInt(str.substring(sysmbolindex[0]+1,sysmbolindex[1]));
 40                 int num3 = Integer.parseInt(str.substring(sysmbolindex[1]+1,sysmbolindex[2]));
 41                 int num4 = Integer.parseInt(str.substring(sysmbolindex[2]+1));
 42                 result = fourNumCalculate(num1,num2,num3,num4,sysmbol[0],sysmbol[1],sysmbol[2]);
 43                 answerList.add(result);
 44             }
 45         }
 46         return answerList;
 47     }
 48     //加法
 49     public static int add(int l, int r){
 50         return l+r;
 51     }
 52     //减法
 53     public static int sub(int l, int r){
 54         return l-r;
 55     }
 56     //乘法
 57     public static int mul(int l, int r){
 58         return l*r;
 59     }
 60     //除法
 61     public static String div(int l, int r){
 62         String result = null;
 63         if(l==0){//被除数等于0
 64             result = "" + 0;
 65         }else if(r==0){//除数等于0
 66             result = "NaN";
 67         }else if(l==r){//等于1的情况
 68             result = "1";
 69         }else if(l<r){//真分数情况
 70             if(maxCommonDivisor(l,r)==1){//已不可化简
 71                 result = l+"/"+r;
 72             }else{//可化简
 73                 int mcd = maxCommonDivisor(l,r);
 74                 int rl = l/mcd;
 75                 int rr = r/mcd;
 76                 result = rl + "/" + rr;
 77             }
 78         }else{//被除数大于除数
 79             int rl = l;
 80             int rr = r;
 81             if(rl%rr==0)//可整除
 82                 result = "" + rl/rr;
 83             else{//不可整除,假分数处理,转化为带分数形式
 84                 if(maxCommonDivisor(l,r)!=1){//有公约数,先化简
 85                     int mcd = maxCommonDivisor(l,r);
 86                     rl = l/mcd;
 87                     rr = r/mcd;
 88                 }
 89                 int c = rl/rr;//除数
 90                 int y = rl%rr;//余数
 91                 result = c + "'"+ y +"/" +rr;
 92             }
 93         }
 94         return result;
 95     }
 96     //辗转相除法求两数最大公约数
 97     public static int maxCommonDivisor(int a, int b){
 98         if(b == 0){
 99             return a;
100         }
101         int r = a%b;
102         return maxCommonDivisor(b,r);
103     }
104     //二元运算
105     public static String twoNumCalculate(int num1, int num2 , char s){
106         String result = "";
107         if(s=='+'){
108             result = "" + add(num1,num2);
109         }else if(s=='-'){
110             result = "" + sub(num1,num2);
111         }else if(s=='*'){
112             result = "" + mul(num1,num2);
113         }else if(s=='/'){
114             result = div(num1,num2);
115         }
116         return result;
117     }
118     //三元运算
119     public static String threeNumCalculate(int num1, int num2, int num3, char c1, char c2){
120         String result = "";
121         if(c1=='+'){
122             switch (c2){
123                 case '+':result = "" + add(add(num1,num2),num3);break;
124                 case '-':result = "" + sub(add(num1,num2),num3);break;
125                 case '*':result = "" + add(num1,mul(num2,num3));break;
126                 case '/':result = div(num1*num3+num2,num3);break;
127             }
128         }else if(c1=='-'){
129             switch (c2){
130                 case '+':result = "" + add(sub(num1,num2),num3);break;
131                 case '-':result = "" + sub(sub(num1,num2),num3);break;
132                 case '*':result = "" + sub(num1,mul(num2,num3));break;
133                 case '/':result = div(num1*num3-num2,num3);break;
134             }
135         }else if(c1=='*'){
136             switch (c2){
137                 case '+':result = "" + add(mul(num1,num2),num3);break;
138                 case '-':result = "" + sub(mul(num1,num2),num3);break;
139                 case '*':result = "" + mul(mul(num1,num2),num3);break;
140                 case '/':result = div(num1*num2,num3);break;
141             }
142         }else if(c1=='/'){
143             switch (c2){
144                 case '+':result = div(num1+num2*num3,num2);break;
145                 case '-':result = div(num1-num2*num3,num2);break;
146                 case '*':result = div(num1*num3,num2);break;
147                 case '/':result = div(num1,num2*num3);break;
148             }
149         }
150         return result;
151     }
152     //四元运算
153     public static String fourNumCalculate(int num1, int num2, int num3, int num4, char c1, char c2, char c3){
154         String result = "";
155         if(c1=='+'){//第一是+
156             if (c2=='+'){
157                 switch (c3){
158                     case '+':result = "" + add(add(add(num1,num2),num3),num4);break;
159                     case '-':result = "" + sub(add(add(num1,num2),num3),num4);break;
160                     case '*':result = "" + add(add(num1,num2),mul(num3,num4));break;
161                     case '/':result = div(add(num1,num2)*num4+num3,num4);break;
162                 }
163             }else if(c2=='-'){
164                 switch (c3){
165                     case '+':result = "" + add(sub(add(num1,num2),num3),num4);break;
166                     case '-':result = "" + sub(sub(add(num1,num2),num3),num4);break;
167                     case '*':result = "" + sub(add(num1,num2),mul(num3,num4));break;
168                     case '/':result = div(add(num1,num2)*num4-num3,num4);break;
169                 }
170             }else if(c2=='*'){
171                 switch (c3){
172                     case '+':result = "" + add(add(num1,mul(num2,num3)),num4);break;
173                     case '-':result = "" + sub(add(num1,mul(num2,num3)),num4);break;
174                     case '*':result = "" + add(num1,mul(mul(num2,num3),num4));break;
175                     case '/':result = div(num1*num4+mul(num2,num3),num4);break;
176                 }
177             }else if(c2=='/'){
178                 switch(c3){
179                     case '+':result = div(add(num1,num4)*num3+num2,num3);break;
180                     case '-':result = div(sub(num1,num4)*num3+num2,num3);break;
181                     case '*':result = div(num1*num3+mul(num2,num4),num3);break;
182                     case '/':result = div(num1*num3*num4+num2,num3*num4);break;
183                 }
184             }
185         }else if(c1=='-'){//第一是-
186             if (c2=='+'){
187                 switch (c3){
188                     case '+':result = "" + (num1-num2+num3+num4);break;
189                     case '-':result = "" + (num1-num2+num3-num4);break;
190                     case '*':result = "" + (num1-num2+num3*num4);break;
191                     case '/':result = div((num1-num2)*num4+num3,num4);break;
192                 }
193             }else if(c2=='-'){
194                 switch (c3){
195                     case '+':result = "" + (num1-num2-num3+num4);break;
196                     case '-':result = "" + (num1-num2-num3-num4);break;
197                     case '*':result = "" + (num1-num2-num3*num4);break;
198                     case '/':result = div((num1-num2)*num4-num3,num4);break;
199                 }
200             }else if(c2=='*'){
201                 switch (c3){
202                     case '+':result = "" + (num1-num2*num3+num4);break;
203                     case '-':result = "" + (num1-num2*num3-num4);break;
204                     case '*':result = "" + (num1-num2*num3*num4);break;
205                     case '/':result = div(num1*num4-num2*num3,num4);break;
206                 }
207             }else if(c2=='/'){
208                 switch(c3){
209                     case '+':result = div((num1+num4)*num3-num2,num3);break;
210                     case '-':result = div((num1-num4)*num3-num2,num3);break;
211                     case '*':result = div(num1*num3-num2*num4,num3);break;
212                     case '/':result = div(num1*num3*num4-num2,num3*num4);break;
213                 }
214             }
215         }else if(c1=='*'){//第一是*
216             if (c2=='+'){
217                 switch (c3){
218                     case '+':result = "" + (num1*num2+num3+num4);break;
219                     case '-':result = "" + (num1*num2+num3-num4);break;
220                     case '*':result = "" + (num1*num2+num3*num4);break;
221                     case '/':result = div(num1*num2*num4+num3,num4);break;
222                 }
223             }else if(c2=='-'){
224                 switch (c3){
225                     case '+':result = "" + (num1*num2-num3+num4);break;
226                     case '-':result = "" + (num1*num2-num3-num4);break;
227                     case '*':result = "" + (num1*num2-num3*num4);break;
228                     case '/':result = div(num1*num2*num4-num3,num4);break;
229                 }
230             }else if(c2=='*'){
231                 switch (c3){
232                     case '+':result = "" + (num1*num2*num3+num4);break;
233                     case '-':result = "" + (num1*num2*num3-num4);break;
234                     case '*':result = "" + (num1*num2*num3*num4);break;
235                     case '/':result = div(num1*num2*num3,num4);break;
236                 }
237             }else if(c2=='/'){
238                 switch(c3){
239                     case '+':result = div(num1*num2+num3*num4,num3);break;
240                     case '-':result = div(num1*num2-num3*num4,num3);break;
241                     case '*':result = div(num1*num2*num4,num3);break;
242                     case '/':result = div(num1*num2,num3*num4);break;
243                 }
244             }
245         }else if(c1=='/'){//第一是/
246             if (c2=='+'){
247                 switch (c3){
248                     case '+':result = div(num1+num2*num3+num2*num4,num2);break;
249                     case '-':result = div(num1+num2*num3-num2*num4,num2);break;
250                     case '*':result = div(num1+num2*num3*num4,num2);break;
251                     case '/':result = div(num1*num4+num2*num3,num2*num4);break;
252                 }
253             }else if(c2=='-'){
254                 switch (c3){
255                     case '+':result = div(num1-num2*num3+num2*num4,num2);break;
256                     case '-':result = div(num1-num2*num3-num2*num4,num2);break;
257                     case '*':result = div(num1-num2*num3*num4,num2);break;
258                     case '/':result = div(num1*num4-num2*num3,num2*num4);break;
259                 }
260             }else if(c2=='*'){
261                 switch (c3){
262                     case '+':result = div(num1*num3+num2*num4,num2);break;
263                     case '-':result = div(num1*num3-num2*num4,num2);break;
264                     case '*':result = div(num1*num3*num4,num2);break;
265                     case '/':result = div(num1*num3,num2*num4);break;
266                 }
267             }else if(c2=='/'){
268                 switch(c3){
269                     case '+':result = div(num1+num2*num3*num4,num2*num3);break;
270                     case '-':result = div(num1-num2*num3*num4,num2*num3);break;
271                     case '*':result = div(num1*num4,num2*num3);break;
272                     case '/':result = div(num1,num2*num3*num4);break;
273                 }
274             }
275         }
276         return result;
277     }
278 }

比较答案的类,其中有读取题目和答案到List的方法,一个比较的方法比较题目计算得到的答案与读取到的答案

 1 public class CompareAnswer {
 2     //验证答案正误,list里面装两个list
 3     public static List<List> compareAnswer(String questionFilepath, String yourAnswerFilepath) throws Exception {
 4         List<List> compareResult = new ArrayList<>();
 5         List<String> correctlist = new ArrayList();
 6         List<String> wronglist = new ArrayList();
 7         List<String> questionlist = questionfile2list(questionFilepath);
 8         List<String> answerlist = Calculator.calculate(questionlist);
 9         List<String> youranswerlist = answerfile2list(yourAnswerFilepath);
10         for(int i=0;i<questionlist.size() && i<answerlist.size();i++){
11             if(answerlist.get(i).equals(youranswerlist.get(i))){
12                 String str =i+1+"";//索引+1变题号
13                 correctlist.add(str);
14             }else{
15                 String str =i+1+"";
16                 wronglist.add(str);
17             }
18         }
19         compareResult.add(correctlist);
20         compareResult.add(wronglist);
21         return compareResult;
22     }
23     public static List<String> questionfile2list(String filepath) throws Exception {
24         List<String> list = new ArrayList<>();
25         FileReader fileReader = new FileReader(filepath);
26         BufferedReader bufferedReader = new BufferedReader(fileReader);
27         String str = null;
28         while ((str=bufferedReader.readLine())!=null){
29             int begin = str.indexOf("、")+1;
30             int end = str.indexOf(" =");
31             str = str.substring(begin,end);
32             str.replaceAll("\\s*","");
33             list.add(str);
34         }
35         return list;
36     }
37     public static List<String> answerfile2list(String filepath) throws Exception {
38         List<String> list = new ArrayList<>();
39         FileReader fileReader = new FileReader(filepath);
40         BufferedReader bufferedReader = new BufferedReader(fileReader);
41         String str = null;
42         while ((str=bufferedReader.readLine())!=null){
43             int begin = str.indexOf("、")+1;
44             str = str.substring(begin);
45             str.replaceAll("\\s*","");
46             list.add(str);
47         }
48         return list;
49     }
50 }

写文件的类,提供三种写文件的方法,它们写入的格式各不相同

public class OutputFile {
    //输出题目文件
    public static void printQuestion(List<String> queList){
        File file = new File("./Exercises.txt");
        questionlist2file(file,queList);
        System.out.println("生成题目成功!");
    }
    //输出答案文件
    public static void printAnswer(List<String> ansList){
        File file = new File("./Answers.txt");
        answerlist2file(file,ansList);
        System.out.println("生成答案成功!");
    }
    //输出答案的比较结果
    public static void printCompareResult(List<List> resultList){
        File file = new File("./Grade.txt");
        compareresultlist2file(file,resultList);
        System.out.println("答案验证完成!");
    }
    //输出题目文件
    public static void questionlist2file(File file, List<String> list){
        int i=1;//行号从1开始
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter(file));
            for (String s : list) {
                writer.write(i+"、"+s+" ="+"\n");
                i++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(writer!=null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //输出答案文件
    public static void answerlist2file(File file, List<String> list){
        int i=1;//行号从1开始
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter(file));
            for (String s : list) {
                writer.write(i+"、"+s+"\n");
                i++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(writer!=null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //输出比较结果文件
    public static void compareresultlist2file(File file, List<List> list){
        BufferedWriter writer = null;
        int sumcorrect=0;
        int sumwrong=0;
        try {
            writer = new BufferedWriter(new FileWriter(file));
            List correct = list.get(0);
            List wrong = list.get(1);
            sumcorrect=correct.size();
            sumwrong=wrong.size();
            writer.write("Correct: "+sumcorrect);
            writer.write(" (");
            for(int i=0;i<correct.size();i++){
                writer.write((String) correct.get(i));
                if(i<correct.size()-1){
                    writer.write(", ");
                }
            }
            writer.write(")");
            writer.write("\n");
            writer.write("Wrong: "+sumwrong);
            writer.write(" (");
            for(int j=0;j<wrong.size();j++){
                writer.write((String) wrong.get(j));
                if(j<wrong.size()-1){
                    writer.write(", ");
                }
            }
            writer.write(")");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(writer!=null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

四、测试运行

  第一种测试:(生成几个题目)

     

    修改几个答案后的比较结果:

    

       

  

   第二种测试:(生成1万道题目)

     

   第三种测试:(生成100万道题目)

    

    

   

  第四种测试:(生成一亿道题目的测试)

    经过测试,在生成一亿道题目过程中:

      CPU几乎占100%,JVM的GC在一小段时间后几乎占100%,内存几乎满;

      在测试进行到6分多钟的时候,出现了GC overhead limit exceeded,没有足够的内存而触发了GC的保护机制

      (JVM花费了98%的时间进行垃圾回收,而只得到2%可用的内存)

     

   运行生成题目和答案代码覆盖率

    

   运行验证答案的代码覆盖率

    

五、效能分析

  生成题目较少时:

    各方法执行时间相差不大,时间有波动

    

   生成一万道题目时:

    经过几次测试,生成题目的方法时间较长

    

  

  生成一百万道题目时:

    经过几次测试,这时输出答案用时较长

    

  资源消耗情况

     十道题目,很普通

     

    一万道题目,也没消耗多少资源

     

     一百万道题目,过程中看到进行了一次GC,资源消耗较大了

     

    一亿道题目(最终没有成功)。CPU爆满,GC爆满,内存爆满。由于安全机制自动停止了。

     

    

六、遇到的困难及解决方法

   比较答案的时候读入题目文件去掉题号和=号时不能去掉英文点

    解决办法:将题号的英文点换成中文顿号

   在写计算类的时候,发现一开始的设计不能不能扩展更多计算符和带括号的题目

    解决办法:没有考虑带括号的题目了,也没有考虑兼容更多符号的题目了;但能够支持数值是两位数甚至更多位的情况

   遇到生成题目保证非负的时候,生成100万道还是有0.63%的错误率

    解决办法:经检查,是因为忽略了/运算符在编程语言里的处理是整除,即11/10的结果是1;经过改正,只要保证有/运算的题目通分后的分子非负即可。

   

七、PSP

PSP

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

· Estimate

· 估计这个任务需要多少时间

 30

 26

Development

开发

· Analysis

· 需求分析 (包括学习新技术)

 120

 148

· Design Spec

· 生成设计文档

 120

 122

· Design Review

· 设计复审 (和同事审核设计文档)

 60

 30

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

10 

10 

· Design

· 具体设计

60 

55 

· Coding

· 具体编码

1000 

 923

· Code Review

· 代码复审

 120

220 

· Test

· 测试(自我测试,修改代码,提交修改)

120 

 190

Reporting

报告

· Test Report

· 测试报告

 30

 45

· Size Measurement

· 计算工作量

 5

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

120 

 111

合计

 1795

 1885

八、项目小结

  本次结对项目,一开始就花了挺长时间进行需求分析,这让我们后面的进展就比较容易。遗憾的是在算法方面我们的程序不够先进,兼容性也不够;也遗憾没有进行查重操作。在查因除法操作产生bug花了比较多时间,万万没想到的是没有熟悉除法/在编程里面的真正含义。

  立新项目感想:

    本次组队项目我更一步了解GitHub的一些操作,更多的了解java编程的用法,印象深刻的记住了编程语言与数学语言的不同;懂得了与合作伙伴沟通的重要性。

  高山项目感想:

  本次组队项目让我近一步学习了GitHub的使用,同时也是我初次尝试java项目,让我对于面向对象编程有了更深入的认识。同时,组队项目也让我深刻的意识到在一个团队中听取和采纳别人的意见,并且从不同想法中择优是软件工程项目中至关重要的。

猜你喜欢

转载自www.cnblogs.com/lixin-xie/p/12595270.html