• Myapp


    一、github地址:https://github.com/jianghailing/rjgcsecondwork

    二、PSP表格:

    PSP2.1

    Personal Software Process Stages

    预估耗时(分钟)

    实际耗时(分钟)

    Planning

    计划

     30

     40

    · Estimate

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

     30

     35

    Development

    开发

     1000

     1130

    · Analysis

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

     60

     60

    · Design Spec

    · 生成设计文档

     40

     40

    · Design Review

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

     20

     20

    · Coding Standard

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

     30

     30

    · Design

    · 具体设计

     60

     80

    · Coding

    · 具体编码

     1000

     1350

    · Code Review

    · 代码复审

     30

     40

    · Test

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

     60

     90

    Reporting

    报告

     40

     40

    · Test Report

    · 测试报告

     30

     30

    · Size Measurement

    · 计算工作量

     20

     20

    · Postmortem & Process Improvement Plan

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

     30

     30

    合计

     

     2480

     3035

    三、效能分析:

    long startTime = System.currentTimeMillis();    //获取开始时间
    
    doSomething();    //测试的代码段
    
    long endTime = System.currentTimeMillis();    //获取结束时间
    
    System.out.println("程序运行时间:" + (endTime - startTime) + "ms"); 

    通过使用上述代码获取1万道题目所花的时间,如下图:

     

    可以看到,生成1万道题目差不多用了1分钟,而对比周边伙伴的执行可以明显对比出我们团队的代码急需改进,因而我们对TestGeneraTor函数里赘诉以及多余代码进行舍去,同时为方便后续管理,将经常执行到的代码单独构成子函数,大大缩减代码长度,帮助检查以及提升代码质量,修改完代码,再执行代码,发现提升了40%的运行速度,同时不跳出BUG窗口,证实改进成功,以下是改进后图:

     

    消耗最大的函数:思路:依旧使用以上代码,以节点形式,统计每一段子函数的执行前以及执行后的运行时间,通过与总程序执行时间的比值推出消耗最大的函数:

     

    从上往下的执行时间分别为:程序总执行时间,变量定义时间,运算符为1时的执行时间,运算符为2时的执行时间,运算符为3时的执行时间

    将五者进行比较后可以大致为:  10:0.1:1.6:2.4:5.9

    可以看出生成程序主要花在生成有3个运算符的流程上,差不多是程序总执行时间的0.75倍

     四、设计实现过程

     

    当拿到题目时,我们首先考虑如何自动生成题目以及如何防止题目重复,而附加题(判断所给题目答案文件对错个数)暂时没有考虑,然而当深入讨论后发现,防止题目重复和附加题可以由NotRepeat( )函数统一实现,也就是将题目以字符串处理存在一致性;接着发现有些执行率较高,如果全都在一个class方法则使得后期管理造成极大的不方便,因而就有Multiplication( ),Division( ),Addition( ),Substraction( )   四则运算函数

    以及ranNum( ),ranOperator( )等辅助函数,同时有Myapp.exe -n 10的命令行传参的需求,所以无心插柳柳成荫,两个间接函数帮忙实现第二个需求,而由于对第一种需求的研究深入,所以在处理第三个需求时可以套用NotRepeat( )函数,完成对给定的题目答案正错个数的统计;

    我们着重考虑对第一种需求的完成,自动生成题目,题目由括号,操作数,运算符以固定字符组成,所以需要从优先级生成前三种字符入手,我们商量后,先用随机函数决定有没有括号,当要有括号后,再用随机函数生成有多少运算符,再次嵌套,决定括号包含第几个运算符,同时由于决定有多少个运算符后,操作数也随着确定数量,所以通过ranNum( )函数生成,由于题目要求不能出现负数,因而对运算符进行筛查,当出现‘ - ’时进行Substraction( ),如果结果为负,则重新生成操作数,当出现连续的‘ - ’运算后,我们当时没想到合适的解决方案,因而只是对所有减数进行乘法运算,减小减数的值来降低出现负数的概率,而我们在调试时也确确实实出现过,因此这是我们后面要做的工作的重点,当三个部分都生成完毕后,题目也自动生成,接着进行NotRepeat(  )函数操作,检查题目以及答案文件是否有该道题目,如果有则重新生成题目TestGenerator(  ),直到不重复为止,第一个需求才真正完成。

    对于第二个需求,从ranNum( )以及ranOperat( )两个函数以参数保障

    对于第三个需求,则需对第一个过程进行微修改,没有题目生成的代码,通过对题目文件的读写,按行获得题目,接着通过遍历的方法,先遍历字符串判断是否有括号,当存在括号后优先考虑括号,算出括号里的数据后,将结果覆盖字符串的内容,未覆盖到的用‘ ’替代,再次遍历逐一获取操作数以及运算符,然后通过for循环依据运算符的优先级对优先级高的算术优先处理,结果存在原进行运算的操作数中,未覆盖的用‘-1’替代,直到整型数组只存在一个数,此时结束,该数就为该题目答案,判断两者答案是否一致,给出对错的序号,以及个数

    五、代码说明

    (1)TestGenerator( ) 

    case 1:{
    
    
         switch(temp2) {//运算符的个数
    
    
         case 1:
    
    
          {
    
    
          operat[1]=ranOperator.Operator();//operat[i]代表第几个运算符
    
    
         num1=ranNum.RanNumber();
    
    
         num2=ranNum.RanNumber();
    
    
            boolean tap=true;
    
    
         while(operat[1]=='-'&&tap==true) {
    
    
         a[0] = num1[0] * num1[2] + num1[1];
    
    
           a[1] = num1[2];
    
    
           b[0] = num2[0] * num2[2] + num2[1];
    
    
           b[1] = num2[2];
    
    
           c[0] = a[0] * b[1] - a[1] * b[0];
    
    
           c[1] = a[1] * b[1];
    
    
           if(c[0]<0) {
    
    
           num1=ranNum.RanNumber();
    
    
               num2=ranNum.RanNumber();
    
    
               tap=true;
    
    
           }else {
    
    
           tap=false;
    
    
           }
    
    
         }
    
    
               //generate代表自动生成的题目
    
    
         Generate = num1[0]+"'"+num1[1]+"/"+num1[2]+operat[1]+num2[0]+"'"+num2[1]+"/"+num2[2]+"=";
    
    
    //System.out.println(Generate);
    
    
         break;
    
    
         }
    
    
         case 2:{
    
    
            temp3=rand1.nextInt(2)+1;//结果是1,表示括号在第一个运算符,2,在第二个运算符
    
    
                if(temp3==1)
    
    
                {
    
    
                 str[0]='(';
    
    
                    str[16]=')';
    
    
                }
    
    
                else {
    
    
                 str[9]='(';
    
    
                    str[25]=')';
    
    
                }
    
    
                {
    
    
             operat[1]=ranOperator.Operator();
    
    
             operat[2]=ranOperator.Operator();
    
    
             num1=ranNum.RanNumber();
    
    
             num2=ranNum.RanNumber();
    
    
             num3=ranNum.RanNumber();
    
    
                boolean tap=true;
    
    
             while(operat[1]=='-'&&tap==true&& operat[2] !='-') {
    
    
             a[0] = num1[0] * num1[2] + num1[1];
    
    
               a[1] = num1[2];
    
    
               b[0] = num2[0] * num2[2] + num2[1];
    
    
               b[1] = num2[2];
    
    
               c[0] = a[0] * b[1] - a[1] * b[0];
    
    
               c[1] = a[1] * b[1];
    
    
               if(c[0]<0) {
    
    
               num1=ranNum.RanNumber();
    
    
                   num2=ranNum.RanNumber();
    
    
                   tap=true;
    
    
               }else {
    
    
               tap=false;
    
    
               }
    
    
             }
    
    
             tap=true;
    
    
             while(operat[2]=='-'&&tap==true &&operat[1] !='-') {
    
    
             a[0] = num2[0] * num2[2] + num2[1];
    
    
               a[1] = num2[2];
    
    
               b[0] = num3[0] * num3[2] + num3[1];
    
    
               b[1] = num3[2];
    
    
               c[0] = a[0] * b[1] - a[1] * b[0];
    
    
               c[1] = a[1] * b[1];
    
    
               if(c[0]<0) {
    
    
               num2=ranNum.RanNumber();
    
    
                   num3=ranNum.RanNumber();
    
    
                   tap=true;
    
    
               }else {
    
    
               tap=false;
    
    
               }
    
    
             }
    
    
             tap=true;
    
    
                     //当运算符为负数时,则需要对操作数进行减法操作,当结果为负数时要重新生成操作数
    
    
             while(operat[2]=='-'&&tap==true &&operat[1] =='-') {
    
    
             while(operat[1]=='-'&&tap==true) {
    
    
             a[0] = num1[0] * num1[2] + num1[1];
    
    
               a[1] = num1[2];
    
    
               b[0] = num2[0] * num2[2] + num2[1];
    
    
               b[1] = num2[2];
    
    
               c[0] = a[0] * b[1] - a[1] * b[0];
    
    
               c[1] = a[1] * b[1];
    
    
               if(c[0]<0) {
    
    
               num1=ranNum.RanNumber();//生成操作数的随机函数
    
    
                   num2=ranNum.RanNumber();
    
    
                   tap=true;
    
    
               }else {
    
    
               tap=false;
    
    
               }
    
    
             }
    
    
             num3[0]=(int)(num2[0]/2);
    
    
             num3[1]=(int)(num2[1]/2);
    
    
             num3[2]=(int)(num2[2]/2);
    
    
            
    
    
               
    
    
               }
    
    
            }    
    
    
                if(temp3==1)
    
    
                {
    
    
              Generate = "("+num1[0]+"'"+num1[1]+"/"+num1[2]+operat[1]+num2[0]+"'"+num2[1]+"/"+num2[2]+")"+operat[2]+num3[0]+"'"+num3[1]+"/"+num3[2]+"=";
    
    
        //System.out.println(Generate);
    
    
                }
    
    
                else {
    
    
                 Generate = num1[0]+"'"+num1[1]+"/"+num1[2]+operat[1]+"("+num2[0]+"'"+num2[1]+"/"+num2[2]+operat[2]+num3[0]+"'"+num3[1]+"/"+num3[2]+")"+"=";
    
    
         //  System.out.println(Generate);
    
    
                }
    
    
                break;
    
    
         }
    
    
         case 3:  {
    
    
            temp3=rand1.nextInt(3)+1;//结果是1,表示括号在第一个运算符,2,在第二个运算符,依次类推
    
    
                if(temp3==1)
    
    
                {
    
    
                 str[0]='(';
    
    
                    str[16]=')';
    
    
                }
    
    
                else if(temp3==2){
    
    
                 str[9]='(';
    
    
                    str[25]=')';
    
    
                }else if(temp3==3) {
    
    
                 str[18]='(';
    
    
                    str[34]=')';
    
    
                }
    
    
                {
    
    
             operat[1]=ranOperator.Operator();
    
    
             operat[2]=ranOperator.Operator();
    
    
             operat[3]=ranOperator.Operator();
    
    
                 num1=ranNum.RanNumber();
    
    
                 num2=ranNum.RanNumber();
    
    
                 num3=ranNum.RanNumber();
    
    
                 num4=ranNum.RanNumber();
    
    
                 boolean tap=true;
    
    
                if(operat[1]=='-'&&tap==true) {
    
    
              num2[0]=num2[0]/2;
    
    
              num2[1]=num2[1]/2;
    
    
              num2[2]=num2[2]/2;
    
    
                }
    
    
                if(operat[2]=='-'&&tap==true) {
    
    
              num3[0]=num3[0]/3;
    
    
              num3[1]=num3[1]/3;
    
    
              num3[2]=num3[2]/3;
    
    
            }
    
    
                if(operat[3]=='-'&&tap==true) {
    
    
              num4[0]=num4[0]/4;
    
    
              num4[1]=num4[1]/4;
    
    
              num4[2]=num4[2]/4;
    
    
              }
    
    
             }
    
    
                
    
    
                if(temp3==1)
    
    
                {
    
    
              Generate = "("+num1[0]+"'"+num1[1]+"/"+num1[2]+operat[1]+num2[0]+"'"+num2[1]+"/"+num2[2]+")"+operat[2]+num3[0]+"'"+num3[1]+"/"+num3[2]+operat[3]+num4[0]+"'"+num4[1]+"/"+num4[2]+"=";
    
    
        //System.out.println(Generate);
    
    
                }
    
    
                else if(temp3==2){
    
    
                 Generate = num1[0]+"'"+num1[1]+"/"+num1[2]+operat[1]+"("+num2[0]+"'"+num2[1]+"/"+num2[2]+operat[2]+num3[0]+"'"+num3[1]+"/"+num3[2]+")"+operat[3]+num4[0]+"'"+num4[1]+"/"+num4[2]+"=";
    
    
          // System.out.println(Generate);
    
    
                }
    
    
                else if(temp3==3){
    
    
                 Generate = num1[0]+"'"+num1[1]+"/"+num1[2]+operat[1]+num2[0]+"'"+num2[1]+"/"+num2[2]+operat[2]+"("+num3[0]+"'"+num2[1]+"/"+num2[2]+operat[3]+num4[0]+"'"+num4[1]+"/"+num4[2]+")"+"=";
    
    
          // System.out.println(Generate);
    
    
                }
    
    
                
    
    
              break;
    
    
         }

    (2)NotRepeat(  )判断题目是否重复

    char sss[] = str.toCharArray();
    
    
             boolean tap=true;
    
    
             for(i=0;i<str.length();i++) {
    
    
              if(sss[i]=='(') {
    
    
              parplace=i;
    
    
              tap=false;
    
    
              }
    
    
              if(tap==false) {
    
    
              str.replace("[0-9]","");
    
    
              }
    
    
              if(sss[i]==')') {
    
    
              tap=true;
    
    
              }
    
    
             }
    
    
             //提取括号里的数字和运算符
    
    
             char s[] = getSignInfo.toCharArray();
    
    
             int parantnum []= {0,0};
    
    
             Pattern p2 =Pattern.compile("^[0-9]*$");
    
    
             Matcher m2 = p2.matcher(getSignInfo);
    
    
             i=0;
    
    
             while (m2.find()) {//通过while循环获得一道题目中的所有数字
    
    
              temp1=m2.group();
    
    
              parantnum[i]=Integer.parseInt(temp1);
    
    
              i++;
    
    
            }
    
    
             //将他们提取到的数字优先计算
    
    
             for(i=0;i<getSignInfo.length();i++) {
    
    
              int j=0;
    
    
                 num1[0]=parantnum[0];
    
    
                 num1[1]=parantnum[1];
    
    
                 num1[2]=parantnum[2];
    
    
                 num2[0]=parantnum[3];
    
    
                 num2[1]=parantnum[4];
    
    
                 num2[2]=parantnum[5];
    
    
              if(s[i]=='+') {
    
    
              num3=Addition.Add(num1,num2);
    
    
              }
    
    
              if(s[i]=='-') {
    
    
              num3=Substraction.Substract(num1,num2);
    
    
              }
    
    
              if(s[i]=='x') {
    
    
              num3=Multiplication.Multiply(num1,num2);
    
    
              }
    
    
              if(s[i]=='÷') {
    
    
              num3=Division.Divide(num1,num2);
    
    
              }
    
    
            }
    
    
              //优先计算完后,将数据存进原先数组中
    
    
                 if(-1 < parplace && parplace < 6) {
    
    
                  num[0]=num3[0];
    
    
                  num[1]=num3[1];
    
    
                  num[2]=num3[2];
    
    
                 }
    
    
                 if(6<=parplace&&parplace<=8) {
    
    
                  num[3]=num3[0];
    
    
                  num[4]=num3[1];
    
    
                  num[5]=num3[2];
    
    
                 }
    
    
                 if(9<=parplace&&parplace<=17) {
    
    
                  num[6]=num3[0];
    
    
                  num[7]=num3[1];
    
    
                  num[8]=num3[2];
    
    
                 }
    
    
                 if(18<=parplace) {
    
    
                  num[9]=num3[0];
    
    
                  num[10]=num3[1];
    
    
                  num[11]=num3[2];
    
    
                 }

     六、测试运行

    (1)Myapp.exe -n 10

    对应的答案文件:answer.txt

    对应的question.txt文件

    (2)Myapp.exe -r 10

    由ranNum( )函数以及ranOperator( )函数

    (3)Myapp.exe -e <question>.txt -a <answer>.txt

    对应的Grade.txt文件

    程序正确性:

        首先,我们小规模测试,每次生成两道题目以及答案,然后人工检验,发现大都正确,少部分因为负数虽然结果正确,但与题目要求不符,故判为错误,即使这样可以保证每道题目的正确性

    七、项目感想

       在项目中,我们两个人互补优缺点,虽然遭到很多BUG的摧残,但终究坚挺完成项目,同时我们都很高兴对项目的优化作用能够使整个项目速度提高40%,以及学会当项目代码过长过多时学会以子函数缩短主函数代码长度,达到后期维护管理的效果,在开发过程也巩固我们的java知识,学习都是要温故而知新,学到以前java课设没涉及到的java知识;我们收获很多,但美中不足,是没有解决负数的问题,我们通过对减数的一半处理降低负数出现的概率,由于我们都是逐一对运算符进行处理,当跨运算符处理就变得束手无策,所以接下来的维护重点在于防止出现负数,对于在此项目所花的时间较第一次软工作业长得多,我们发现我们开发时间都花在重新整理思路,以及对各种BUG的修改上,所有我们的java基础尚浅,今后还需通过作业以及实验提高我们的代码效率以及代码质量,以任务驱动作为我们学习的动力帮助我们很好地运用java,更好开发优质代码。

    项目成员:布雷斯(3117209003),江海灵(3117004658)

     

  • 相关阅读:
    浏览器是怎样工作的二:渲染引擎 HTML解析(1)(转)
    凯文.都迪的超级记忆力训练教程
    程序员的修炼之道
    我编程我快乐——程序员的职业规划
    SQL Server 数据库备份和还原认识和总结(一)
    SQL Server 管理数据收集
    汇总SQL Server里的相关运算符、子句、谓词等
    SQL Server 数据库备份和还原认识和总结(二)
    解决报表控件报CS0433错误
    通过笔记本配件,理解抽象类接口和委托事件
  • 原文地址:https://www.cnblogs.com/1430559825qqcom/p/11689649.html
Copyright © 2020-2023  润新知