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)
Myapp的更多相关文章
- 将MyApp.exe和Autorun.lnk添加到NK里,在project.bib文件内加入
1. 将应用程序和应用程序快捷方式添加到映像里,再将快捷方式添加到StartUp目录下,这样当系统运行后应用程序就能自动运行:2. 直接替换Wince的SHELL,即修改注册表: [HKEY_LOCA ...
- Maven 搭建与my-app项目测试
前提条件,安装jdk1.6及以上版本,并配置JAVA_HOME 首先,下载Maven3.2.2,附下载地址:http://mirror.bit.edu.cn/apache/maven/maven-3/ ...
- No matching provisioning profiles found for "Applications/MyApp.app”问题解决
新开发的一个app打包报错,度娘谷歌了好久,废了不少时间,发现错误提示已经很明显了,只是自己没读懂而已,先说下问题和解决方法,给同意遇到这个问题的你: Failed to locate or gene ...
- myapp——自动生成小学四则运算题目的命令行程序(侯国鑫 谢嘉帆)
1.Github项目地址 https://github.com/baiyexing/myapp.git 2.功能要求 题目:实现一个自动生成小学四则运算题目的命令行程序 功能(已全部实现) 使用 -n ...
- Tomcat报错: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/myApp]]
Tomcat报错:严重: A child container failed during startjava.util.concurrent.ExecutionException: org.apach ...
- EntityFramework codefirst Enable-Migrations No context type was found in the assembly “MyApp.Web” error
Enable-Migrations -Force -ContextTypeName "MyApp.Repository.DataContext" -ProjectName &quo ...
- ng-app与ng-app='myApp'的区别
ng-app与ng-app=""是一样的,都是没定义应用名的,例如 <div ng-app="" ng-init="firstName='ech ...
- NS3 MyApp Class Reference
官方文档:MyApp 可以在下面的几个例子找到: examples/tutorial/fifth.cc examples/tutorial/seventh.cc examples/tutorial/s ...
- 假设web应用的文档根目录为MyApp,那么可以从哪里找到database.jar文件。
假设web应用的文档根目录为MyApp,那么可以从哪里找到database.jar文件. A. MyApp目录下 B. MyApp\images目录下 C. MyApp\WEB-INF目录下 D. M ...
- Unable to execute dex: Multiple dex files define Lcom/myapp/R$array;
Unable to execute dex: Multiple dex files define Lcom/myapp/R$array; 我这个问题最后解决方式是,吧工程里面用同一个v4包. 很明显, ...
随机推荐
- 11/4 <LinkedList>
82. Remove Duplicates from Sorted List II 跳过重复节点,返回head. class Solution { public ListNode deleteDupl ...
- 6.Go-错误,defer,panic和recover
6.1.错误 Go语言中使用builtin包下error接口作为错误类型 Go语言中错误都作为方法/函数的返回值 自定义错误类型 //Learn_Go/main.go package main imp ...
- 微信小程序入门笔记
目录的作用: 1. pages目录: 该目录下存放所有的定义页面 2. utils目录: 该目录下存放定义的一些小功能组件 3. 根目录下app.js文件: 定义小程序对象, 执行小程序生命周期内的各 ...
- Python爬虫爬取数据的步骤
爬虫: 网络爬虫是捜索引擎抓取系统(Baidu.Google等)的重要组成部分.主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份. 步骤: 第一步:获取网页链接 1.观察需要爬取的多 ...
- Linux性能优化实战学习笔记:第五十讲
一.上节回顾 上一节,我以 ksoftirqd CPU 使用率高的问题为例,带你一起学习了内核线程 CPU 使用率高时的分析方法.先简单回顾一下. 当碰到内核线程的资源使用异常时,很多常用的进程级性能 ...
- 图论问题(1) : hdu 1198
题目转自hdu 1198,题目传送门 题目大意: 给你11种单位水管摆放位置,若上下或左右有水管连接则视为这两点相连. 最后让你求这些张图中有几个连通块. 解题思路: 本来觉得这道题很简单,不就一个建 ...
- [LeetCode] 395. Longest Substring with At Least K Repeating Characters 至少有K个重复字符的最长子字符串
Find the length of the longest substring T of a given string (consists of lowercase letters only) su ...
- withDefaultPasswordEncoder() 过时弃用问题
在学springsecurity5.X时,在demo里,内存配置用户的时候,提示withDefaultPasswordEncoder过时,特查看了源码,官方给出的理由是: /** @deprecate ...
- qt no doubments matching "ui..h" could be found
问题情境描述: 自己单独添加的UI文件,然后添加一个类来使用这个UI文件,第一次输入UI Form名称时是大写,被添加到工程里面就是大写, 大写的情况下,添加action转到槽就会提示这个错误. 修改 ...
- 推荐一款语音直播连麦App YAMI
推荐一款语音直播连麦App YAMI 1 介绍 功能描述:[语音直播]:海量超有才主播,游戏送礼抢红包,嗨玩不停:[多人聊天室]:连麦交友处CP,主持人带你玩游戏,边聊边玩:[语音交友]:海量声优专属 ...