软件工程的个人项目是写一个面向小学生的四则运算题目生成和校验工具。主要功能有两个,一是生成四则运算题目,二是对给定的题目和答案,校验其中答案的正确性。
时间表格
前期构思的时间比较多,但是在编码和测试中还是花费了不少的时间。
由于采用的c语言,在字符串的处理和内存管理上花费了较多的时间。
PSP2.1 |
Personal Software Process Stages |
Time |
Planning |
计划 |
|
· Estimate |
· 估计这个任务需要多少时间 |
20h |
Development |
开发 |
|
· Analysis |
· 需求分析 (包括学习新技术) |
6h |
· Design Spec |
· 生成设计文档 |
1h |
· Design Review |
· 设计复审 (和同事审核设计文档) |
1h |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
0.5h |
· Design |
· 具体设计 |
2h |
· Coding |
· 具体编码 |
7h |
· Code Review |
· 代码复审 |
1h |
· Test |
· 测试(自我测试,修改代码,提交修改) |
4h |
Reporting |
报告 |
|
· Test Report |
· 测试报告 |
1h |
· Size Measurement |
· 计算工作量 |
0.5h |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
0.5h |
合计 |
24.5 |
题目分析和思路
主要问题:
1.算式查重
非等价去重
如果两个表达式的数和操作符都一样,我们认为这两个表达式重复。
2.对大量数据的支持,支持1w个算式,考虑到查重需要顺序检索,使用结构体和链表
3.答案校对需要支持对中缀表达式的计算
1)中缀表达式转后缀表达式——调度场算法
2)后缀表达式的计算
4.真分数的四则运算(a!=0,b!=0)
获取操作数:a,b,m,n
计算结果:k,l(k/l的形式)
1)加减法:m/a + n/b -> (bm+an)/ab
乘法:m/a × n/b ->mn/ab
除法:m/a ÷ n/b ->mb/na(n!=0)
2)辗转相除法求得最大公约数,化简分数(k/l)
if(k>l) x=gcd(k,l); else x=gcd(l,k);
int gcd(int k, int l){ if(k%l==0) return l; else return gcd(l,k%l); }
另:另记得处理化简之后分母为1的情况
5.括号问题——生成带括号的算式
左括号:第一个数/每一个操作符(不含最后一个),若没有生成过左括号,随机一次是否生成左括号。
右括号:每一个操作符,若生成过左括号没有生成过右括号,随机一次是否生成右括号。
结尾处:若已经有左括号但是没有右括号,则补上右括号。
备注:先检测右括号,后检测左括号。
6.c语言带来的需要注意的问题:c风格式字符串处理,内存管理。
代码中遇到的问题
1.生成过程中的算式结果合法性检查花费了大量的时间。很多时间花在对生成到一半的表达式进行处理使其成为能够计算的表达式。
2.处理c风格式字符串与生俱来的麻烦,这点在上一点中也有很大影响。
3.内存管理问题。为了简化代码,构写了不少函数,传参和返回值基本采用char*类型,释放内存的过程中产生了不少问题。
性能分析
ArithmeticProducer.exe -r 50 -n 20000
名称 |
非独占样本数 |
独占样本数 |
非独占样本数百分比 |
独占样本数百分比 |
- ArithmeticProducer.exe |
1,159 |
624 |
100.00 |
53.84 |
+ produce |
969 |
532 |
83.61 |
45.90 |
+ _strcmp |
18 |
18 |
1.55 |
1.55 |
+ gcd |
18 |
18 |
1.55 |
1.55 |
+ calc |
152 |
16 |
13.11 |
1.38 |
+ convert |
25 |
13 |
2.16 |
1.12 |
+ transToVulgarFrac |
59 |
8 |
5.09 |
0.69 |
+ getRand |
16 |
7 |
1.38 |
0.60 |
+ getGcd |
22 |
4 |
1.90 |
0.35 |
+ _RTC_CheckEsp |
2 |
2 |
0.17 |
0.17 |
+ getIntResult |
109 |
2 |
9.40 |
0.17 |
+ @ILT+230 |
1 |
1 |
0.09 |
0.09 |
+ @ILT+240 |
1 |
1 |
0.09 |
0.09 |
+ _RTC_CheckStackVars |
1 |
1 |
0.09 |
0.09 |
+ checkRange |
91 |
1 |
7.85 |
0.09 |
+ __tmainCRTStartup |
1,159 |
0 |
100.00 |
0.00 |
+ main |
1,159 |
0 |
100.00 |
0.00 |
+ mainCRTStartup |
1,159 |
0 |
100.00 |
0.00 |
其中produce()是用于生成算式的函数。
从上述性能分析数据来看,占据CPU时间最多的produce()函数,占比高达45.90%。
其它函数中,CPU时间主要耗费在计算上(gcd()用于递归计算最大公约数,clac()用于计算后缀表达式的值,convert()用于将中缀表达式转换为后缀表达式以便计算)。
根据分析数据,produce()函数有很大的优化空间。