第一单元总结
第一单元总结
在这个单元的作业主要任务是化简表达式,拆开括号并化简。
第一次作业
基本思路
本次作业中我参考了训练中递归下降的方法,用Lexer类来读取字符,用Parser类来解析并存储表达式的各个部分。我在第一次作业中把表达式分为Expr、Term、Variable三个层次,每个层次实现了一个use方法来递归化简,最终将结果转化成一个存储Variable的HashMap,这样可以处理多层括号的情况,方便扩展。
对于核心的use方法来说,Expr中的use处理好其中每个Term,将处理好的Term储存在一起;Term中的use主要完成了核心的去括号过程,对于幂函数,我将n次幂拆成了n个相乘的形式,之后用multipy方法将每个Factor相乘的结果计算出来,最终将Term转化为Variable相加;而Variable的use则是返回他本身。于是对最顶层的Expr调用use方法就可以得到化简之后的表达式。
代码分析
体量分析
Source File | Total Lines | Source Code Lines | Source Code Lines [%] |
Expr.java | 107 | 94 | 0.8785046728971962 |
Factor.java | 11 | 7 | 0.6363636363636364 |
Lexer.java | 70 | 64 | 0.9142857142857143 |
MainClass.java | 16 | 13 | 0.8125 |
Parser.java | 128 | 117 | 0.9140625 |
Term.java | 83 | 70 | 0.8433734939759037 |
Variable.java | 39 | 31 | 0.7948717948717948 |
度量分析(标红的部分)
method | CogC | ev(G) | iv(G) | v(G) |
expr.Expr.toString() | 40.0 | 2.0 | 20.0 | 21.0 |
Lexer.Lexer(String) | 20.0 | 6.0 | 7.0 | 8.0 |
expr.Term.use() | 19.0 | 3.0 | 13.0 | 13.0 |
Parser.parseFactor() | 5.0 | 5.0 | 5.0 | 5.0 |
在Lexer和parseFactor中,我使用了很多if-else导致复杂度较高;而剩下两个部分则是因为化简导致复杂度较高
UML类图
架构整体来说比较清晰,具有一定的可扩展性
bug分析
在处理幂函数的时候有一个笔误,导致0次方有时候会出问题;同时在此次作业中未能发现别人的bug。
第二次作业
基本思路
本次作业加入了三角函数,自定义函数和求和函数。对于自定义函数,我在一开始将其储存起来,使用时先在Func类里解析出形参和实参,之后将实参代入函数表达式,使用Lexer和Parser对新字符串解析,返回一个Expr。对于求和函数,也采取类似的方法进行处理。对于三角函数,我将基础结构由Variable改为Variable*Πsin()*Πcos()的形式,之后修改了Term类中的multiply方法,基本上就能实现三角函数的基础化简。
代码分析
体量分析
Source File | Total Lines | Source Code Lines | Source Code Lines [%] |
Expr.java | 144 | 129 | 0.8958333333333334 |
Factor.java | 14 | 9 | 0.6428571428571429 |
Func.java | 44 | 39 | 0.8863636363636364 |
Lexer.java | 79 | 73 | 0.9240506329113924 |
MainClass.java | 27 | 21 | 0.7777777777777778 |
Parser.java | 308 | 292 | 0.948051948051948 |
Sum.java | 60 | 51 | 0.85 |
Term.java | 115 | 102 | 0.8869565217391304 |
Tri.java | 127 | 115 | 0.905511811023622 |
VarAndTri.java | 95 | 78 | 0.8210526315789474 |
Variable.java | 72 | 61 | 0.8472222222222222 |
可以看出Parser类的行数过多,这是因为此次作业中这部分重复的代码过多,可以进行优化。
度量分析(标红部分)
method | CogC | ev(G) | iv(G) | v(G) |
expr.Term.mult(ArrayList, ArrayList) | 27.0 | 1.0 | 8.0 | 9.0 |
expr.Expr.print() | 24.0 | 4.0 | 11.0 | 13.0 |
expr.Tri.sSin() | 22.0 | 1.0 | 10.0 | 10.0 |
expr.Variable.toString() | 21.0 | 1.0 | 11.0 | 11.0 |
Lexer.Lexer(String) | 20.0 | 6.0 | 7.0 | 8.0 |
expr.Term.use() | 19.0 | 3.0 | 13.0 | 13.0 |
expr.Tri.sCos() | 19.0 | 1.0 | 9.0 | 9.0 |
Parser.getCos() | 17.0 | 1.0 | 9.0 | 9.0 |
Parser.getSin() | 17.0 | 1.0 | 9.0 | 9.0 |
Lexer.next() | 15.0 | 2.0 | 14.0 | 19.0 |
Parser.parseFactor() | 10.0 | 9.0 | 11.0 | 11.0 |
这次作业我的程序复杂度较高,一方面是由于加入了新内容,导致读入解析、化简时的复杂度上升;另一方面,我代码中有一些重复的地方,同时三角函数内部的处理完成得不是很好,导致出现了一些bug。
UML类图
bug分析
这次作业中我在强测中就出现了好几个bug。第一个是在三角函数内没有考虑带符号的情况,主要是由于没有在测试前做足够的测试。第二个是深克隆的问题,在对一个因子进行处理时会影响其他的项,我在测试时发现了这个问题但是在截至时间之前没有想出原因。第三个是没有将sin(0)**0设为1。
由于我这次作业完成得不好,所以被分到了C房,输入一些比较基础的数据就能找到别人的bug。例如在sin(-x),有好几位同学都和我一样没有考虑这方面的问题。
第三次作业
基本思路
这次作业主要要求实现函数的嵌套、三角函数的嵌套还有多层括号的嵌套,大部分内容在之前的作业中已经可以实现,因此没有做太多修改。这次作业主要修改了三角函数内的部分,之前使用Variable存储,现在采用String存储,这样能够存储更多内容,而解析方式也改成了读入字符串用Lexer和Parser解析。
代码分析
体量分析
Source File | Total Lines | Source Code Lines | Source Code Lines [%] |
Expr.java | 171 | 160 | 0.935672514619883 |
Factor.java | 14 | 9 | 0.6428571428571429 |
Func.java | 57 | 50 | 0.8771929824561403 |
Lexer.java | 79 | 73 | 0.9240506329113924 |
MainClass.java | 27 | 21 | 0.7777777777777778 |
Parser.java | 249 | 233 | 0.9357429718875502 |
Sum.java | 63 | 54 | 0.8571428571428571 |
Term.java | 114 | 101 | 0.8859649122807017 |
Tri.java | 114 | 103 | 0.9035087719298246 |
VarAndTri.java | 91 | 75 | 0.8241758241758241 |
Variable.java | 72 | 61 | 0.8472222222222222 |
进行了部分优化,相比与第二次作业行数有所减少。
度量分析(标红部分)
method | CogC | ev(G) | iv(G) | v(G) |
expr.Expr.toString() | 45.0 | 3.0 | 23.0 | 24.0 |
expr.Term.multiply(ArrayList, ArrayList) | 27.0 | 1.0 | 8.0 | 9.0 |
expr.Variable.toString() | 21.0 | 1.0 | 11.0 | 11.0 |
Lexer.Lexer(String) | 20.0 | 6.0 | 7.0 | 8.0 |
expr.Term.use() | 20.0 | 3.0 | 14.0 | 14.0 |
expr.Tri.sCos() | 20.0 | 1.0 | 12.0 | 12.0 |
Lexer.next() | 15.0 | 2.0 | 14.0 | 19.0 |
expr.Tri.sSin() | 15.0 | 1.0 | 10.0 | 10.0 |
Parser.parseFactor() | 10.0 | 9.0 | 11.0 | 11.0 |
这次作业中我在toString中又加了一些化简内容,导致复杂度高;圈复杂度高的部分主要是由于读入输出时各种判断导致if-else语句使用过多。
UML类图
第三次作业的UML与上一次相比并无太多变化。
bug分析
这次作业我有两处bug。第一处是sum上下限未考虑范围,采用了int,导致数据过大时会报错;第二处是sum中替换i时没有加括号导致负数会出错。主要还是因为没有考虑全面而产生问题,之后应该注重测试的覆盖程度。
hack别人时发现有一位同学在处理sin(-x)时没有加括号,可能是由于优化时没有考虑到这种情况导致出错。
心得体会
这是我第一次使用面向对象的思想完成并迭代程序。这个单元的学习让我意识到好的架构的重要性,优秀的架构具有良好的可扩展性,可以让迭代优化变得比较容易。
在这一单元的作业中,我还有许多做得不够好的地方。比如测试方面有所欠缺、优化程度不够高、没有去限制程序复杂度。在下个单元的学习中我会着重去弥补这一单元做得不够好的地方。