四则运算项目个人反思总结
原项目链接:
http://www.cnblogs.com/jiel/p/4810756.html
一、PSP2.1表格
PSP | Estimate Time | Actual Time |
Planning | 10min | |
Development | ||
Analysis | 45min | 30min |
Design Spec | 15min | 12min |
Design Review | 2min | 2min |
Coding Standard | 0 | 0 |
Design | 1h | 1h |
Coding | 1h | 5h |
Code Review |
10min |
0.5h |
Test | 30min | 6h |
Reporting | ||
Test Report | 30min | 30min |
Size Measurement | 10min | 10min |
Postmortem & Process Improvement Plan | 30min | 30min |
total | 5h | 14h24min |
PSP2.1表格对于我来说还是比较陌生的东西,虽然写了,但是实际开发有些环节其实并没有重视起来,但是由于这点被忽略导致我付出了惨重的代价(这个后面会谈到)。
二、开发心路历程
一开始觉得这个程序应该比较简单,就是用一个随机函数生成一个表达式,然后对表达式进行分析,把中缀表达式转换成后缀表达式,最后进行计算即可。
后来开始设计的时候发现我想得还是太简单了。
第一个遇到的大的问题是怎样生成随机数,我最开始直接是这样写的:
#define random(x) (rand() % x)
这样生成的随机数全部都是伪随机数,而且有个问题就是每次程序运行生成的算式都是完全一样的!
后来在网上查了资料才知道这是由于计算机总是根据一个特定的种子来生成随机数,而且生成随机数的方式是固定的,因此每次运行总是得到相同的结果。
修改如下,加入一条代码:
srand((unsigned)time(NULL));
这样就可以生成不同的算式了。
第二个遇到的问题就是怎样支持分数运算,我的想法是将整数和带分数统一成假分数,整数看成分母为1的假分数,这样就可以统一用带分数来进行运算了。
数据的存储结构用一个二维数组来存储,二维数组第二维为0代表分子,为1代表分母。对于加法和减法运算,统一以两个分母的乘积为公分母通分,进行运算以后再进行约分操作。
除法直接调换除数的分子和分母即可。
第三个问题就是如何避免出现重复,我的解决方法是将所有算式的括号方式进行归纳总结,一共有8种加括号的方式,我用一个参数来调控具体生成算式用哪一种加括号的方式,然后保证算式的数字和括号方式不能完全雷同,这样就可以避免生成同样的算式。
第四个问题就是中缀表达式转后缀表达式的问题,因为本程序要处理的符号中分数线和除号要分开处理,因此涉及到一个取出元素的问题,这个没有什么算法难度,但是细节的问题很多,因此后面调试付出了不少时间。
写代码如上所述,5h,600+行的代码,写得比较痛苦,因为需要不断地改之前的设计,细化很多之前设计没有想清楚的东西。导致代码没有一气呵成,而且自己写代码的风格不太好,变量命名没有太多规律,可能会导致最后自己也看不懂自己在写什么。。。
最蛋疼的就是调试了,最开始写下来编译错误一大堆,改完编译错误运行起来又是崩溃崩溃再崩溃,不过还好我以前积累了一些编程经验,通过中间输出变量结果和单步调试结合起来的方式,查错比较快,但归纳起来的错误就两类:变量没有初始化,循环变量没有及时++,导致死循环。
三、性能分析
VS2012出了些问题,没法进行代码分析,稍后会补上。
四、测试样例
输入:
1.((96 + 55) + 20) × 56 =
2.((43 × 13) × 62) × 56 =
3.36 × (35 - 12 ÷ 15) =
4.(49 ÷ 21) × (63 ÷ 21) =
5.73 ÷ (11 + 53 + 1) =
6.(5 + 19) × 82 ÷ 28 =
7.80 + (30 + 2 + 7) =
输出:
1.9576
2.1940848
3.1231'1/5
4.7
5.1'8/65
6.70'2/7
7.119
说明:1 – 7 的测试用例覆盖了所有的加减乘除运算,并且覆盖了几乎所有的括号的位置,且答案出现了大数(1940848)以及分数(1231’1/5,1’8/65,70’2/7)。
输入:
8. (0 ÷ 21) × (63 ÷ 21) =
输出 :
0
说明:考虑答案为零的情况。
输入:
9. (1’1/2 ÷ 2/3) × (1 + 2) = 3
输出:
Correct
说明:检查是否能对输入含有分数正确处理。
输入:
10.1 + 2 + 3 – 4 = 2
输出:
Correct
说明:检查没有括号能否处理。
五、反思总结
这次个人项目给我的教训还是很深刻的,以前我们写的代码都是两三百行,算法比较简单,也不需要很复杂的数据结构,所以脑袋里大概想一想怎么编就开始码代码了。而这次的项目是有一定的难度的,代码量也不小,所以导致最后写的代码质量不高,可维护性也很差。
另外,对于C++的内置标准库我了解得也不是很多,它提供的一些常用的String类型的操作我也不是很熟悉,因此很多函数都是自己从底层实现的,其实如果熟悉了C++提供的操作也许就是一行代码的事情,因此,模板化编程是我应该学习的编程手段。
---恢复内容开始---
四则运算项目个人反思总结
原项目链接:
http://www.cnblogs.com/jiel/p/4810756.html
一、PSP2.1表格
PSP | Estimate Time | Actual Time |
Planning | 10min | |
Development | ||
Analysis | 45min | 30min |
Design Spec | 15min | 12min |
Design Review | 2min | 2min |
Coding Standard | 0 | 0 |
Design | 1h | 1h |
Coding | 1h | 5h |
Code Review |
10min |
0.5h |
Test | 30min | 6h |
Reporting | ||
Test Report | 30min | 30min |
Size Measurement | 10min | 10min |
Postmortem & Process Improvement Plan | 30min | 30min |
total | 5h | 14h24min |
PSP2.1表格对于我来说还是比较陌生的东西,虽然写了,但是实际开发有些环节其实并没有重视起来,但是由于这点被忽略导致我付出了惨重的代价(这个后面会谈到)。
二、开发心路历程
一开始觉得这个程序应该比较简单,就是用一个随机函数生成一个表达式,然后对表达式进行分析,把中缀表达式转换成后缀表达式,最后进行计算即可。
后来开始设计的时候发现我想得还是太简单了。
第一个遇到的大的问题是怎样生成随机数,我最开始直接是这样写的:
#define random(x) (rand() % x)
这样生成的随机数全部都是伪随机数,而且有个问题就是每次程序运行生成的算式都是完全一样的!
后来在网上查了资料才知道这是由于计算机总是根据一个特定的种子来生成随机数,而且生成随机数的方式是固定的,因此每次运行总是得到相同的结果。
修改如下,加入一条代码:
srand((unsigned)time(NULL));
这样就可以生成不同的算式了。
第二个遇到的问题就是怎样支持分数运算,我的想法是将整数和带分数统一成假分数,整数看成分母为1的假分数,这样就可以统一用带分数来进行运算了。
数据的存储结构用一个二维数组来存储,二维数组第二维为0代表分子,为1代表分母。对于加法和减法运算,统一以两个分母的乘积为公分母通分,进行运算以后再进行约分操作。
除法直接调换除数的分子和分母即可。
第三个问题就是如何避免出现重复,我的解决方法是将所有算式的括号方式进行归纳总结,一共有8种加括号的方式,我用一个参数来调控具体生成算式用哪一种加括号的方式,然后保证算式的数字和括号方式不能完全雷同,这样就可以避免生成同样的算式。
第四个问题就是中缀表达式转后缀表达式的问题,因为本程序要处理的符号中分数线和除号要分开处理,因此涉及到一个取出元素的问题,这个没有什么算法难度,但是细节的问题很多,因此后面调试付出了不少时间。
写代码如上所述,5h,600+行的代码,写得比较痛苦,因为需要不断地改之前的设计,细化很多之前设计没有想清楚的东西。导致代码没有一气呵成,而且自己写代码的风格不太好,变量命名没有太多规律,可能会导致最后自己也看不懂自己在写什么。。。
最蛋疼的就是调试了,最开始写下来编译错误一大堆,改完编译错误运行起来又是崩溃崩溃再崩溃,不过还好我以前积累了一些编程经验,通过中间输出变量结果和单步调试结合起来的方式,查错比较快,但归纳起来的错误就两类:变量没有初始化,循环变量没有及时++,导致死循环。
三、性能分析
四、测试样例
输入:
1.((96 + 55) + 20) × 56 =
2.((43 × 13) × 62) × 56 =
3.36 × (35 - 12 ÷ 15) =
4.(49 ÷ 21) × (63 ÷ 21) =
5.73 ÷ (11 + 53 + 1) =
6.(5 + 19) × 82 ÷ 28 =
7.80 + (30 + 2 + 7) =
输出:
1.9576
2.1940848
3.1231'1/5
4.7
5.1'8/65
6.70'2/7
7.119
说明:1 – 7 的测试用例覆盖了所有的加减乘除运算,并且覆盖了几乎所有的括号的位置,且答案出现了大数(1940848)以及分数(1231’1/5,1’8/65,70’2/7)。
输入:
8. (0 ÷ 21) × (63 ÷ 21) =
输出 :
0
说明:考虑答案为零的情况。
输入:
9. (1’1/2 ÷ 2/3) × (1 + 2) = 3
输出:
Correct
说明:检查是否能对输入含有分数正确处理。
输入:
10.1 + 2 + 3 – 4 = 2
输出:
Correct
说明:检查没有括号能否处理。
五、反思总结
这次个人项目给我的教训还是很深刻的,以前我们写的代码都是两三百行,算法比较简单,也不需要很复杂的数据结构,所以脑袋里大概想一想怎么编就开始码代码了。而这次的项目是有一定的难度的,代码量也不小,所以导致最后写的代码质量不高,可维护性也很差。
另外,对于C++的内置标准库我了解得也不是很多,它提供的一些常用的String类型的操作我也不是很熟悉,因此很多函数都是自己从底层实现的,其实如果熟悉了C++提供的操作也许就是一行代码的事情,因此,模板化编程是我应该学习的编程手段。