OO课程第一次作业表达式求导
目录
我使用的方法简介:
1.预备知识
dfs深度优先的搜索
2.为什么要选择这个方法
1.设计简单:不会涉及到对象之间复杂的交互,而交互就容易带来问题
2.非常可靠:这是一种广泛使用的语法分析方法,可以相信它的拓展能力
3.先举一个例子
$x*x+x*x$ 求导
3.1向下求导
先从后向前找到第一个$+$
分解为$x * x$与$x * x$
左式从后向前找到第一个$*$分解为$x$与$x$
右式从后向前找到第一个$*$分解为$x$与$x$
左式的左边执行求导发现是基本项$x$求导为$1$
同理左式的右边,右式的左边,右式的右边也被求导
3.2向上合并
左式乘法合并就是$x * 1 + 1 * x$
右式乘法合并就是$x * 1 + 1 * x$
整个式子合并就是左式加右式
4.基本的架构思路:
1.整个函数叫$parse$的话。分解出左式右式后执行 $parse(左式)$,$prase(右式)$ 并根据中间的符号合并
2.我们能执行到找乘法的for的已经先把所有的加减法都去除了,能执行到找乘法的$for$之后的已经先把所有的乘除法都去除了,还能执行的只有基本情况了比如$1$, $x$, $sin(x)$。但我实际上实现的时候是先判别的这样可以减少分类的压力
3.为了简单起见我向上合并的项只有一种类型$Term$,它的核心是$private Map<String, BigInteger>$
关于面向对象
类图
耦合度
class | OCavg | WMC |
Main | 5.444444444444445 | 49.0 |
ParsePare | 1.9166666666666667 | 23.0 |
StringHelper | 2.3076923076923075 | 30.0 |
Term | 2.935483870967742 | 91.0 |
Tester | 3.6666666666666665 | 11.0 |
Total | 204.0 | |
Average | 3.0 | 40.8 |
质量分析
我理解的OO技术更接近于使用高内聚低耦合进行对于代码细节,质量上的提高,不是简单的类之间去传递信息就叫OO了。但是在我这方面做的不是很好,写出的并不是理想的规范化的程序。尤其是我的Term为了化简有大量的if形成了很大的WMC,Main由于我的设计原因,相当于集成了原本六个类的功能WMC也不小。代码应当有大量重构,比如Main还是应当分解,这样便于测试与维护,Term内的化简部分重构则比较困难了。
使用的对象创建模式
我的ParsePare其实就用到了工厂模式。它本来是一个括号解析器。它能够正向也可以反向的进行解析,可以一次插入一个字符也可以一次解析完一个字符串。我通过它的构造函数传入的参数区别了这几个情况,能方便的生产需要的方法。
三次作业遇到的BUG
第二次作业
1.没有考虑其它空字符:垂直制表符等
2.出现了空对象:在修改化简部分时有一部分特判空与特判指数的代码位置交换了,而特判指数的代码又不支持特判空
3.指数范围特判的处理:求导之后,我会重新解析一次以期简化,但他们复用了同一段代码,-100次方求导是-101次方,抛出异常。
第三次作业
1.关于加减WF判断错误:对于加法解析我会尽量去除加号(维护首项,项首的使用机会)。第三次作业没有理解之前设计的意图,给乘法解析增加了使用机会。
2.解析函数:由于sin里只能是项而我把()视为了恒等函数一起处理了,所以()里不是项就会抛异常。
互测感想
其实就是把指导书上所有的特殊情况进行组合,并合成一些比较长的式子层次比较深的式子,就足以卡出很多bug了
自我评价
最开始选择这个架构的主要原因是我很熟悉,并且我相信科学库里也是这么实现的。加上我上学期选修了java程序设计基础自以为面向对象写的还可以了,以为可以试试在实际的使用OO技术。但直到最后才觉得连门都没摸到。自己的思路被之前见过的递归下降的代码限制太深了(我并没有见过它的工程代码)。其实这个做法和课程一般的做法区别并不大,无非就是两个解析的方式不同。其实弄到最后就是课程组推荐的做法,事实上我的代码相当于把表达式项呀什么的都集成到Main中了,由于已经分解成函数了,和再分成那几个类差不多了,而向上合并只用Term表示也没毛病。