2019OO第一单元总结

第一次作业

 (你没看错,就一个类。。。)

通过正则表达式处理输入的字符串,提取出每一项的系数和指数,在输出的时候,应当考虑到合并同类项和正项提前的问题,使得最终的输出最短。

我第一次作业的代码超级难看,在互测的时候看了别人的代码之后,自己的代码连我自己都看不下去了。在第一次作业的代码中,我只用了一个主类Main,在主方法中用大正则识别表达式、判断合法性、求导,毫无对象概念,根本没有体现出面向对象的特性,同样也在互测环节中被查出来很多bug。所以在第二次作业中,我决定使用面向对象的思想,对代码进行一次彻底的重构。

 

公测没有查出bug,但是在互测环节被hack惨了。

最主要的问题就是输入x-x或者123这类求导结果为0的公式没有输出的问题,其次还有特殊字符、正则爆栈的问题,其中第一个问题是最明显的问题。这是因为我在写程序的时候没有模块化的概念,完完全全是面向过程式的写法,导致自己的程序很不清晰。在自己写完代码、通过弱侧之后,应当自己编写测试点并测试,而我显然是因为没做好在本地机器上测试的工作,才会出现这么明显的bug。

  

第二次作业

与第一次作业类似,在输入完公式之后进行化简,使得每一项都是t*x^a*sin(x)^b*cos(x)^c的形式,然后进行求导,最后再合并同类项,把正项提前输出。但是,应当注意+++123是一个合法的公式,可以看作第一个加号是项的符号,第二个加号是"1*"的省略,第三个加号是123的符号,应当特殊处理一下。

我使用了4个类:Main主类;Exp公式类,由很多Term通过加法构成;Term项类,由很多Factor通过乘法构成;Factor因子类,里面有一个枚举变量,用于区分这是什么类型的因子。

公测还是没查出bug,但是在互测环节被别人查出来了。

这一次的bug明显比第一次少了,但是还有bug,在公式末尾为+或-的时候,会产生异常(由于str.indexOf(i)越界了)。

  

第三次作业

由于这次作业需要支持函数嵌套,因此在第二次作业的基础上,进行了大量的改造。

我使用了5个类:Main主类;Exp公式类,由很多Term通过加法构成;Term项类,由很多Nest通过乘法构成;Nest类,是很多Func的嵌套,还包含了exp代表嵌套在最里层的公式;Func函数类,由第二次作业的Factor改造而成,把常数看作常值函数,仍然用枚举变量的方式区分不同的函数。

对于Exp公式类的求导,就是对其中的Term求导然后相加;对于Term的求导,通过乘法的求导法则,最终返回一个Exp;对于Nest的求导,通过链式法则,最终返回一个Term。

同样地,公测还是全AC,互测被查出来了bug,在Nest最后如果是sin(x) ^ +2这样,^和指数的符号中间有空格的时候会出现问题,是因为我在空格的地方没有处理好。

 

总结

通过观察这三次作业的UML图和Class Metrics表,可以看出第二、三次作业相比第一次作业的进步很大(第一次作业我就不说什么了),这三次作业的bug全是出现在表中标红的地方,在接下来的程序中,我应当改进程序的逻辑,使得程序质量得到提高,逻辑更加清晰。

  

互测发现别人bug的策略

我用PowerShell写了一个自动测试的脚本,用Python写了一个表达式求导的程序和判断两个公式是否相等的程序(都是用的Sympy库),在第三次作业中查出了别人求导结果错误的地方。

test.ps1内容如下

$rootPath=$(pwd).Path
$name="sympy","archer","assassin","berserker","caster","lancer","rider","saber"
$entrance="","Main","Main","Main","Main","Main","Main","Main" # 把这里稍微改一下,因为有些人主类不是Main
$ans=0..7
for(;;) {
   cd $rootPath
   $str=Read-Host
   if($str -eq "init") {
       for($i=1;$i -le 7;$i++) {
           echo "Compiling $($name[$i])"
           cd "$rootPath\$($name[$i])\src"
           javac -encoding utf-8 (dir . -recurse -name *.java)
           echo ""
       }
       echo "finish"
       continue
   } elseif($str -eq "exit") {
       exit
   }

   echo "***$($name[0])***:"
   $ans[0]=(echo $str|python $rootPath\ans.py)
   echo $ans[0]
   echo ""

   for($i=1;$i -le 7;$i++) {
       echo "$($name[$i]):"
       cd "$rootPath\$($name[$i])\src"
       $ans[$i]=(echo $str|java $entrance[$i]|Select-Object -First 1)
       echo $ans[$i]
       cd $rootPath
       if($ans[$i] -ne "WRONG FORMAT!") {
           echo $ans[0] $ans[$i]|python check.py
       }
       echo ""
   }
}

ans.py内容如下

from sympy import *
x = Symbol('x')
str = input()
print(diff(str, x))

check.py参考了评测机的评测方式,内容如下

from sympy import *
import random
str1 = input()
str2 = input()
expr1 = simplify(str1)
expr2 = simplify(str2)
flag = true
for i in range(0,100):
   tmp = random.uniform(-10,10)
   r1 = expr1.evalf(subs={'x':tmp})
   r2 = expr2.evalf(subs={'x':tmp})
   if abs(r1-r2) > 0.0001:
       flag = false
       break
if flag == true:
   print("AC")
else:
   print("WA")

重构和改进的措施

对于第一次作业而言,我可以使用Exp公式类和Term项类,而不是我原来的完全面向过程的方式,使得自己在编程的时候不容易出现bug。

第二次作业和第三次作业完全可以使用继承的方式,而不是使用枚举变量,这样可以让我的程序看起来更清晰,更能体现面向对象的思想。

对于第二次作业而言,我可以使用sin(x)^2+cos(x)^2=1这个恒等式,对求导结果进行化简,使得输出长度更短。

对于第三次作业而言,我可以把含有0的Term删除,把所有最终为常数的Nest乘在一起,可以让最终结果更短。

这三次作业的bug都出现在程序特别”面向过程“的部分,我应当对其进行改造。

posted @ 2019-03-27 20:20  H3PO4  阅读(228)  评论(0编辑  收藏  举报