第一单元作业总结

第一次作业

题目要求

       第一次作业要求实现简单的多项式求导计算,且保证输入格式一定正确。

实现思路

  使用Item类来作为“项”,其中包含coef(系数)和index(指数)两个属性,这两个属性可以确定一个“项”。然后我用Poly类来作为“多项式”,维护一个Item类型的集合,多项式即代表集合中所有项相加。还有一个Regex类用来将输入的字符串解析为一个Poly对象。最后是MainClass类,在其main方法中将输入、解析、求导、输出这一过程串联起来。

UML类图如下:

 

多项式的化简,只需要关注一些特定的点就可以:同类项合并,零不输出,乘1省略,第一项放正项等等。

 

代码度量分析

Type Name

NOF

NOPF

NOM

NOPM

LOC

WMC

NC

DIT

LCOM

FANIN

FANOUT

Item

2

0

11

11

92

24

0

0

0.181818

0

0

MainClass

0

0

1

1

17

1

0

0

-1

0

0

Poly

1

0

6

6

62

13

0

0

0

0

0

Regex

11

0

10

10

128

18

0

0

0.4

0

0

 

 

 

 

 

Bug

第一次作业在强测中被找出bug,是正则表达式在匹配时产生了栈溢出。我是用一个正则表达式对整个式子进行匹配,其中用到了“*”使得匹配过程变得艰难。后来发现在我的正则表达式的逻辑中,完全可以将“*”变成“?”,能产生同样的效果,效率却大大提升,也不会再产生栈溢出错误。

找别人bug的时候,一开始我还不会用sympy,而是用java做了一个”测试房间”,用来产生数据---用此数据测试屋内所有人的代码---用自己写的Regex类将他们的输出解析为Poly对象---比对这些Poly对象有没有和自己不同的。如果一个测试数据只有1-2人与自己不同,那么大概率是他们错了;如果所有人都和我不同,那就是我错了。

反思

       在第一次作业中,我将空格出现的所有情况都写在了正则表达式里。后来从同学那里学到了预处理的方法,一开始去掉所有空格,把连续的+-号化为1个等等,觉得自己之前的办法太累赘了。后来预处理的方法用到了作业二中。

 

第二次作业

题目要求

       第二次作业在第一次作业的基础上,加入了sin和cos,且不保证输入格式正确。

实现思路

正余弦的计算较为简单,只需要在原来Item类中加入sinIndex和cosIndex两个属性。检验格式也好办,因为不会出现因为空格而导致的WF,所以只需要先去掉所有空格,然后用一整串正则表达式来匹配;对于幂次的限制,只需要在解析字符串的过程中,发现幂次超值,抛出异常。难点在于表达式的化简,因为三角函数变换规则较为灵活,不像作业1有唯一确定的化简道路。

       相比于作业1,新填加了Simplify类用来完成化简工作,SimplifyRule接口,以及SimplifyRule1和SimplifyRule2两个实现SimplifyRule接口的具体化简规则。UML类图如下:

 

 

化简

第二次作业的化简,使用了深搜+熔断来实现。首先有两个化简规则,1:;2:。对当前的多项式,检验每两项是否可以用规则1或规则2进行变形,如果可以,那么进行变形,并沿此搜索下去。使用一个HashMap来记录已经得到过的表达式,并通过minPoly和minPolyLength来记录当前得到的所有表达式中最短的表达式和它的长度。如果变形后的表达式在HashMap中能找到对应,说明之前得到过了,那么回溯。每得到一个表达式,比较是否比minPoly更短,短的话将minPoly更新为当前表达式。设置了最长的搜索时间和最深递归层数,如果超过时间,那么不再搜索,输出minPoly即可。

 

代码度量分析

Type Name

NOF

NOPF

NOM

NOPM

LOC

WMC

NC

DIT

LCOM

Item

4

0

23

23

205

52

0

0

0

MainClass

0

0

1

1

24

2

0

0

-1

Poly

1

0

10

10

76

20

0

0

0

Regex

15

0

13

13

151

24

0

0

0.307692

Simplify

6

0

4

4

64

16

0

0

0.5

SimplifyRule

0

0

2

2

4

2

0

0

-1

SimplifyRule1

5

0

3

3

48

5

0

0

0

SimplifyRule2

5

0

3

3

74

10

0

0

0

 

Bug

第二次作业依然是在强测中被找出bug,bug是由垂直制表符引起的,我没有输出WF。后来才知道,java正则里的\s不只代表空格,而是代表了、、、等空白符号。之后将“\s”改为“ ”解决了bug。

找别人bug,使用了sympy进行自动测试,使用xeger产生测试数据。将发现的bug保存到单独的文件中。

 

反思

如果到了后边,表达式形式变得更自由,尤其是如果出现嵌套的情况,使用“三元组“就不太好办了。果然,第三次作业出现了嵌套,于是不得不重构了……..

 

 

 

第三次作业

题目要求

在第二次作业的基础上,加入了表达式因子;对空格格式的正确性不再保证。

实现思路

       因为有了嵌套,所以原来三元组的思路不能使用了。进行了重构。Term接口,内部定义了求导、变号、合并等方法。常数项ConstTerm、幂函数项PowerTerm、三角函数项TrigTerm、连加项PlusTerm、连乘项MulTerm实现Term接口,而SinTerm和CosTerm继承TrigTerm。在可能会嵌套的地方,比如sin(),在SinTerm里存一个Term表示嵌套的内容。

       如此管理数据,相当于建立了一颗树,那么使用递归完成求导操作。

       由于对空格格式的正确性不再保证,所以不可以一开始去掉所有空格,必须先验证格式正确性,再去空格。于是把格式验证分开进行。首先单独验证空格格式的正确性,因为指导书已经给出空格格式错误的所有情况,所以只需遍历这些情况,只要中了一条,就抛出异常,只有顺利通过检测,才删掉字符串中所有空格,进行下一步。

       字符串解析在Analysis类中完成。由于含有嵌套括号,所以首先将每个最外层括号包含的内容,替换为特殊符号@,然后对替换后的字符串用正则来匹配。接下来使用递归解析每个@所代表的表达式。

  初始化和解析类的类图如下:

 

 

代码度量分析

Type Name

NOF

NOPF

NOM

NOPM

LOC

WMC

NC

DIT

LCOM

FANIN

FANOUT

MainClass

0

0

1

1

25

1

0

0

-1

0

3

ConstTerm

2

1

10

10

58

14

0

1

0.3

8

3

CosTerm

1

1

9

9

107

21

0

2

0.666667

3

6

MulTerm

4

1

14

13

258

58

0

1

0.142857

6

5

PlusTerm

2

1

13

13

126

32

0

1

0.230769

3

5

PowerTerm

2

1

9

9

78

17

0

1

0.333333

3

5

SinTerm

1

1

9

9

104

21

0

2

0.888889

3

6

Term

0

0

6

6

15

6

5

0

-1

10

1

TrigTerm

2

0

5

5

23

5

2

1

0.6

0

1

Analysis

19

0

7

7

190

35

0

0

0

2

10

MyString

3

0

3

3

56

11

0

0

0

1

0

PreTreat

12

0

5

5

97

17

0

0

0.4

2

1

Resource

7

7

0

0

16

0

0

0

-1

7

2

Bug

本次作业被测出来的bug是,输入在cos、sin里面的表达式因子没有再嵌一层括号的时候,我没有检测出来格式错误。

找别人bug的时候,是自己构造一些特殊数据来hack。

反思

  凡事要提前做,不要拖到最后。我这次提交前一小时又改了些东西,结果最后提交得非常仓促。

       我将解析每种类型因子的解析方法都放在了Analysis类中,使得每次改动其中一个解析方法时,都需要满文件上下翻。如果要添加更多的因子类型(虽然后续不再有求导的作业了),就必须得在Analysis里面增加代码,这违背了开放-封闭原则。我认为更好的办法是,为每一种因子单独建立一个解析类,只负责对本因子的解析。改动一个因子的解析,只需要进入相应的类进行改动;增加一个因子,也只需增加因子类和解析类即可。和“工厂方法模式“类似。

posted @ 2020-03-21 21:45  WYO  阅读(261)  评论(1编辑  收藏  举报