OO第一单元作业(表达式求导)总结

一:第一部分,OO作业分析

1. 第一次作业

  第一次作业在在设计的过程中只放了四个类,一个主类,一个输入类,一个item类,一个expression类。由于这里的表达式仅包含有幂函数、常数,而且不需要支持嵌套,于是仅需将每个item做成常数项*幂函数项,这样在读取表达式的时候也可以做合并,于是便不需要factor这个类,便都可以轻松处理。第一次作业还是有一些面向过程的感觉,这样做的结果就是使得自己的代码的扩展能力很差,当后面修改需求之后,又需要额外的大量修改。

  这里的存储的方式也十分简单,如下,用power和para进行存储相应的幂次,和系数,求导起来也十分简单。

public class Item{
     private power;
     private para;          
}

类图如下:

类方法复杂度图如下:

  在复杂度分析上,这里可以看出,我在写的过程了也写了不少的功能方法,也将各个功能分割开,但是最复杂的方法为最后的输出,因为这里的输出需要考虑到前置正好,以及正项前移等问题,却杂合在一起,于是便十分的复杂。

优缺点分析:

   但在这样的编写的思路下,整个工程的功能也比较完善和准确,对于输入格式的检查以及简化等等功能也将其放入了输入类中,在格式检查中,并没有采用大正则的方式,而是采用了一项项寻找合法项并且删除的模式,这样避免了正则爆栈的风险。并且在检查的过程中较有条理,首先检查空格是否会有错误,在检查完毕后,将空字符全部清楚,再进一步检查格式。同时为x补充省略的系数,以及省略的指数,从而使得所有项格式完全统一,简化了后续的工作。


 

2. 第二次作业

  第二次作业,主要是在第一次作业的基础上引入了sin,和cos函数,同时不支持嵌套,此时就有需要区分sin,cos,幂函数,常数项了,并且针对不同的因子,进行不同的求导操作,于是这里我也补充了Factor类,但是并没有使用面向对象中的继承等机制,而是选择了类似C语言中的Union的结构,通过type量来区分不同的factor的类型,这个时候还没有对面向对象有具体的体会,具体的类图如下。

  这里的存储结构由于没有使用继承,而是使用类似Union的结构,通过type来区分factor类型。

public class Factor{
    private type;    // stand for the type;
    private para;    // stand for the parameter c
    private pow;    // stand for the power when it is sin or x
    private pow2;    // stand for the cos
}

类图

复杂度分析如下:

  如上给出了表达式,项,因子等方法的复杂度,可以看出有许多的类还是非常复杂的,比如提取相关的符号,提取需要打印的字符串等等,同样在item中也涉及到了一些类型上的选择,这也使得类的复杂程度非常高。

优缺点分析:

  这里也有两个类,Judge类,和Simplication类,这两个类是我用来做优化的类,Judge类的功能是用于判断是否可以优化,而simplication类来完成相应的优化的过程,这里我原本采用的是深搜的方法来完成表达式的优化,针对sin^2+cos^2 和 1-sin^2,1-cos^2等模型展开树的结构进行搜索,但是面对极端数据,搜索时间会远超过要求时间,最终也退而求其次,限制其深度,与可能性。这里的类的复杂程度仍然来源于我将四种factor融合在一个类中,每次在进行运算前,都需要进行非常繁琐的判断其类型。


 

3 第三次作业

  第三次作业,这次作业增加了嵌套,并且在学习继承等机制后,也是首次尝试使用这类机制进行编写程序。

  于是需要进行相应的设计,需要把不同的因子类继承于相同的父类的结构,这样在编写以及使用相应的求导的过程会十分的简单。

  可以看出,这里在使用了继承机制之后,类之间开始高度的耦合在一起,继承、复用、重写等,都使得程序更加的清晰容易理解。再衡量复杂程度的时候,复杂度就大大降低了。

优缺点分析:

  说明继承等机制和高度的耦合的写法,使得我的程序保持清晰的前提下,能够具有很好的性能。

总结:这三次作业对面向对象的写法也有了初步的认识和进步,能够使用对象的一些特性来完成一些功能,进阶式的一步步完成一些问题。


 

二:第二部分 bug分析

第一次作业:

  目前已知的bug仅在于第一次作业的前置空字符。

  在处理前置空字符的时候,原本采用的是

str = str.trim();

  这样处理掉前后的空白字符,但是后续了解到,这样的作法会使得去除掉一些非法的空字符,于是后续又删除了这个方法。

  由于表达式的格式统一的问题,若第一项没有符号的时候,需要额外增加一个正号来使得所有的格式一致,就需要判断第一个字符是不是正负号,如果不是则需添加一个。但是由于上述的去除空字符的语句已经删掉了,忘记了再次检验第一个字符可能是空字符的情况,于是在开始的地方又额外增加了一个加号进去,产生了三个加号,所以最后这里报了bug。后修改过程中,删除了字符串前的所有合法空字符后再进行判断,便消除了bug。


 

第二次作业:

  没有发现bug,但是在优化中存在不足

  在优化的过程中由于采用深搜的方法,如果可能性过多,深度过深,会早成处理时间过长的问题,如下样例

sin(x)^2+sin(x)^4+sin(x)^6+sin(x)^8+sin(x)^10+sin(x)^12+sin(x)^14+sin(x)^16+sin(x)^18

  这样的一段代码,在求导之后,即存在有1-sin^x的优化的可能性,便将不断的搜索,实际上其合并之后又不会缩短他的长度,于是便陷入了无效的递归中,花费了大量的时间,最后发现不可优化。所以深搜就会产生这样的问题,担心强测中有类似的测试点,便降低了深搜的深度,保证自己代码的运行时间。


 

第三次作业:

  暂无发现


 

三:第三部分 测试策略

   测试策略主要分成格式审查和正确性检查,格式审查,即判断是否会产生wrong format,而正确性检查即对正确样例求导后是否可以产生正确的结果。

格式审查:

  格式审查,在前两次的作业中,格式尚可根据正则表达式进行相应的处理,也可使用相应的正则表达式产生符合格式的样例进行测试,但是这样存在有一定的问题,正则表达式也是自己的写的,这一步无法保证正确性,这样自己检测自己是盲目的,所以在格式检查部分,主要还是根据指导书给出的一些边界条件,例如,因子的定义,指数的省略,系数的省略,有符号整数的空格问题。

  于是根据这些边界条件,主要依靠手动的设计符号要求的样例,进行测试。

正确性审查:

  正确性审查需要借助matlab与python等工具,自己构造类似的评测机制,来完成自己的正确性的检查。

  python可以构造合法的输入的表达式,并且可以通过如下python下的系统调用,完成对JAVA程序的操作

os.system("cat {}|java Main>temp.txt".format(file))

  通过将数据进行重定向给Java程序,并且将其输出暂时存储起来。接着需要对该表达式使用正确的工具进行求导,并且将求导的结果导出。如matlab

matlab -nojvm -nodesktop -nodisplay -r differ

  这里调用matlab程序进行处理,differ为相应的函数,设置对应的参数,即可将数据传入给matlab,让matlab进行测试,并且返回相应的结果。这样从而可以实现正确性的检查,也基于这样的测试,目前也没有出现过正确性上的问题。

四:第四部分 Applying Creational Pattern

   创建型模型抽象了对象实例化的过程。可以帮助一个系统独立的创建、组合、和表示其对象,这个问题在我们的这个第三次作业,也可以的好很好的应用。

  例如我们可以创建一个工厂模式,我们的所有的项,因子,表达式,都是图中的一个节点,于是可以做为在工厂模型中分别创建,并且每个节点之间的运算,例如add,sub,mult,以及嵌套,都可以使用工厂模式完成这些内容的组织。

  这样做的好处是,可以把该系统具体使用哪些具体类的信息进行封装起来。

  

posted @ 2019-03-26 17:00  Ti-amo  阅读(257)  评论(0)    收藏  举报