BUAA_OO_第一单元总结

BUAA_OO_第一单元总结

  第一单元主要目标是进行表达式解析。最终结果为完成能够提供自定义函数、求和函数、三角函数、幂函数及其嵌套的表达式解析程序。

第一次作业

作业要求

  完成一个能够展开包含常数和幂函数的表达式的程序。其中常数为为带符号整数,幂函数为自变量为x,系数为0到8的可包含正号的整数。

类图分析

1.UML

  • MainClass函数为程序入口,提供了表达式读入的功能。然后调用Expression,传入读入的表达式。
  • Expression类在构造时就进行表达式解析,首先去除空格和多余的加减号,替换'**'以防解析错误。然后通过加减号分割,递归下降解析Term。将结果的Poly类相加或相减.
  • Term类在构造时就完成解析,通过乘号分割,递归下降解析Factor。将结果的Poly类进行向乘。
  • Factor类在构造时就完成解析。解析因子所带的正负号、类型(常数因子、变量因子、表达式因子)、指数。然后转化成Poly类进行储存。
  • Poly类通过一个简单的数组进行储存。通过数组下标表示指数,数组内容储存系数。

代码度量

class OCavg OCmax WMC
Expression 4.4 11.0 22.0
Factor 3.0 5.0 6.0
MainClass 1.0 1.0 1.0
Poly 3.125 10.0 25.0
Term 3.0 5.0 6.0
Total 60.0
Average 3.3333333333333335 6.4 12.0
总行数 代码行数 代码行数占比 注释行数 注释行数占比 空白行数 空白行数占比
Expression.java 82 75 0.9146341463414634 2 0.024390243902439025 5 0.06097560975609756
Factor.java 43 36 0.8372093023255814 4 0.09302325581395349 3 0.06976744186046512
MainClass.java 12 10 0.8333333333333334 0 0.0 2 0.16666666666666666
Poly.java 95 86 0.9052631578947369 0 0.0 9 0.09473684210526316
Term.java 28 24 0.8571428571428571 2 0.07142857142857142 2 0.07142857142857142

BUG分析

  第一次作业在强测和互测中并没有出现bug。但是在性能上有部分缺陷。例如x**2到x*x的优化,表达式第一个项应该取符号为正的项的优化。

第二次作业

作业要求

  第二次作业在第一次作业的基础上引入了三角函数、自定义函数和求和函数。仍然不要求多层嵌套括号的解析。三角函数包含sin和cos。求和函数自变量为i,上下限为正整数。自定义函数包含定义和调用。

类图分析

  • MainClass为程序入口,首先进行了实例化Function类储存自定义函数。然后调用Expression类进行解析。
  • Expression类、Term类在表达式处理方式与第一次作业相同。
  • Factor类解析表达式时,除了第一次作业的解析方式外,增加了三角函数的解析。自定义函数调用、求和函数的解析分别调用Function类和Sum类进行解析。
  • Function类搜索自变量,和调用的因子进行匹配,将定义的表达式中的自变量因子进行替换,然后调用Expression类进行解析。
  • Sum类搜索自变量i,在求和表达式中将i替换为求和上下限范围中每一个整数,调用Expression类进行解析,然后将结果求和。
  • Poly与第一次作业类似,但是由于三角函数的引入,储存的系数更改为TriExpression类。
  • TriExpression类储存各个TriTerm。整个类储存了一个三角函数表达式,表示为\(\sum TriTerm\)
  • TriTerm类储存了一个常数和两个map,分别表示除三角函数外的系数和相乘的sin因子和cos因子。整个类储存了一个三角函数项,表示为\(const\prod sin(expression)\prod cos(expression)\)

代码度量

class OCavg OCmax WMC
Expression 4.4 11.0 22.0
Factor 4.5 8.0 9.0
Function 3.5 4.0 7.0
MainClass 2.0 2.0 2.0
Poly 2.6 8.0 26.0
Sum 3.0 4.0 6.0
Term 3.0 5.0 6.0
TriExpression 2.0 4.0 18.0
TriTerm 3.0 13.0 33.0
Total 129.0
Average 2.9318181818181817 6.555555555555555 14.333333333333334
总行数 代码行数 代码行数占比 注释行数 注释行数占比 空白行数 空白行数占比
Expression.java 84 76 0.9047619047619048 2 0.023809523809523808 6 0.07142857142857142
Factor.java 60 50 0.8333333333333334 7 0.11666666666666667 3 0.05
Function.java 46 43 0.9347826086956522 0 0.0 3 0.06521739130434782
MainClass.java 20 17 0.85 0 0.0 3 0.15
Poly.java 122 110 0.9016393442622951 1 0.00819672131147541 11 0.09016393442622951
Sum.java 37 34 0.918918918918919 0 0.0 3 0.08108108108108109
Term.java 30 25 0.8333333333333334 2 0.06666666666666667 3 0.1
TriExpression.java 88 77 0.875 0 0.0 11 0.125
TriTerm.java 183 166 0.907103825136612 5 0.0273224043715847 12 0.06557377049180328

BUG分析

  第二次由于考虑不周在强测和互测中都被hack了。bug出现在sum函数的解析上。我采用了正则表达式解析sum的方式。上下限为带符号整数,在正则匹配时却没有匹配正号,因而导致了bug的产生。

第三次作业

作业要求

  第三次作业要求支持括号的嵌套。其中包括表达式因子、三角函数因子、自定义函数调用内嵌套多层的括号。同时拓展了sum的上下限范围限制。

类图分析

  • 第三次作业架构与第二次作业基本相同,只是在部分类中做了修改。
  • 首先是在Function和Sum类中,针对了自变量做了HashMap。该Map储存了自变量名称和调用时该自变量所代入的值。
  • Factor类中增加了匹配上述自变量Map并替换其值的功能。
  • 在TriTerm类中增加了toString时需要对表达式因子两侧增加括号的功能。

代码度量

class OCavg OCmax WMC
Expression 4.4 11.0 22.0
Factor 7.0 13.0 14.0
Function 4.0 6.0 12.0
MainClass 2.0 2.0 2.0
Poly 2.6 8.0 26.0
Sum 2.5 3.0 5.0
Term 3.0 5.0 6.0
TriExpression 2.0 4.0 18.0
TriTerm 3.25 13.0 39.0
Total 144.0
Average 3.130434782608696 7.222222222222222 16.0
总行数 代码行数 代码行数占比 注释行数 注释行数占比 空白行数 空白行数占比
Expression.java 84 76 0.9047619047619048 2 0.023809523809523808 6 0.07142857142857142
Factor.java 80 66 0.825 11 0.1375 3 0.0375
Function.java 64 60 0.9375 0 0.0 4 0.0625
MainClass.java 20 18 0.9 0 0.0 2 0.1
Poly.java 123 111 0.9024390243902439 1 0.008130081300813009 11 0.08943089430894309
Sum.java 33 30 0.9090909090909091 0 0.0 3 0.09090909090909091
Term.java 30 25 0.8333333333333334 2 0.06666666666666667 3 0.1
TriExpression.java 90 79 0.8777777777777778 0 0.0 11 0.12222222222222222
TriTerm.java 205 186 0.9073170731707317 5 0.024390243902439025 14 0.06829268292682927
Total: 729 651 0.8930041152263375 21 0.02880658436213992 57 0.07818930041152264

BUG分析

  第三次作业在强测和互测收到Hack比较严重,主要问题出在两个方面。
  第一个方面是Sum函数中的上下限出现了bug,一是没有考虑负整数的情况,二是没有考虑到上下限为极大数的情况。还有就是Sum函数上限大于下限的情况,但是这个bug并没有遭到hack。
  第二个方面是优化问题。在三角函数中,如果存在x+1,x**2+1等情况需要在两侧加括号。但是由于设计问题,我在输出时只考虑了序号大于0时的加、减、乘号,因而遇到了-x等情况就没有在两侧加上括号,而出了bug。

单元总结

架构设计

  总体采用了递归下降的方式,从表达式到项再到因子,然后存在嵌套继续调用表达式解析。该递归下降的架构在后来进行迭代时,使代码有更好的扩展性。只需要增删部分方法就能够满足更多的功能。
  从第一到第二次作业仅增加了自定义函数和求和函数的类,在因子解析时进行调用。然后将系数转换为三角函数表达式。第二次作业到第三次作业仅是完成了部分优化,代码在总体上几乎没有进行调整。

测评方式

  我在第一次作业中依照作业的定义,对每部分的边界数据进行了汇总,然后排列组合手搓了小部分数据进行测试。于此同时,我也参考了GitHub上部分学长学姐的测评机,利用python进行了测评机的构建。
  自动测评机主要包括两个部分,第一部分是数据生成器。首先通过random类进行选择生成哪种类型的数据,然后利用xger函数进行各种部分的数据生成。xger利用正则表达式生成相符合的字符串。将各种因子的正则表达提前进行定义就能够较快的生成数据。
  第二部分是对拍程序。通过subprogress将生成的数据传入自己的程序,然后读出输出的数据。同时利用sympy库中的expand函数将生成的数据完全展开,并且展开程序输出的数据,比对两个结果的等价性。将程序的结果:超时、异常、结果不同等问题数据和输出结果写入保存结果的文件中,便于重现bug。
  测评机在三次作业中都给予了我许多的帮助,在测试自己程序的正确性和互测中都起了较大的作用。利用该测评机,我在作业完成后都进行了较多的数据测试,因而除了由于审题问题和格式问题,测评机能够找出我程序的大部分bug,减少因程序不严谨而产生的问题。在互测中,我虽然进行了部分程序的阅读,但是由于程序的复杂性,都难以完全了解别人的程序。但是利用测评机,我在三次作业中都能够利用暴力测试发现许多同学的bug,发现了部分同学程序的错误或者较弱的拓展性。

感想总结

  • 从架构的角度来看,一个好的架构对于程序的迭代开发具有极大的意义。在第一单元中,我都没有做过重构,但是仍能够较为清晰的完成程序。并且在第一第二次作业中完成了嵌套的功能,使得我在第三次的作业中几乎不需要进行调整。但是这也使得我花了较少的时间与精力在第三次作业的审题上,因而忽略了求和函数的限制变化。
  • 从优化的角度来看,需要权量优化和正确性,进行取舍。第三次作业由于时间投入少,对于优化没有进行较好的处理,只是较为简单的判断了符号的存在,因而导致了部分情况没有考虑到位。因而需要权衡取舍程序的性能和正确性。同时在确定优化后,必须更加注意优化的正确性。在以后测评机中,可以考虑增加判断输出格式正确性的功能。
  • 从代码的角度来看,我的代码在许多类中的操作复杂度仍很高,许许多多的方法都没有抽象出来,仍然还有面向过程的方式存在,在面对复杂对象是,没有办法很好的抽象、分割类和方法。
posted @ 2022-03-24 19:51  吴伟泽  阅读(58)  评论(0编辑  收藏  举报