本单元的任务为求导。html
即将一个含自变量x的多项式F求导成为另一个含自变量x的多项式f。使得 dF/dx = f正则表达式
为下降咱们的难度,这个任务被分解成了三个阶段:算法
(1)对幂函数进行求导(不容许嵌套)express
(2)对幂函数和三角函数进行求导(不容许嵌套,三角函数中只能有x)vim
(3)对幂函数和三角函数进行求导(容许嵌套,三角函数中只能有因子)数组
1、聊聊思路函数
一、字符串处理:工具
在第一和第二个阶段中,对输入的处理时相对比较容易的,由于咱们可使用正则表达式对整个输入字符串进行匹配。测试
以第一阶段为例,咱们能够将每一个项分为三种状况 数字、x^n、a*x^n。这里的n能够为任何值,甚至能够在等于1的时候直接省略。spa
那么这三种状况能够分别匹配两个正则表达式:“[+-]?[0-9]+”,“([+-]?[0-9]?\\s*\\*\\s*)[x]\\s*(^\\s*[+-][0-9]?)?”,第二个正则表达式匹配后三种状况(了解更多关于正则表达式)
可是在第三阶段中,因为嵌套的出现,除非在处理过程当中作很是严格的限制将正则表达式分析的范围进行缩减,不然正则表达式没法完成对函数嵌套的字符串处理。
好比对于如下文法:
A::=aAb|i
那么咱们理所固然的写正则表达式A="i",A="a"+A+"b"。在这两条正则表达式的字符串匹配完了以后,咱们发现其实A里面并不包含着嵌套的内容,它仅仅只能匹配"aib",而不能匹配“aaibb”。固然,这是一个很是简单的例子,能够用其余的方法来解决这个问题。然而任务中的状况比这个要复杂的多,举这个例子也只是为了阐明在这个阶段不适合使用正则表达式罢了。
这个时候应该用上另一项利器,词法分析。在计算机编译程序中,一般就是使用词法分析对输入程序进行处理。(了解更多关于词法分析)
二、求导处理:
因为在前一个部分中,三个阶段使用了两种不一样的方法对字符串进行处理,在这个部分依旧分开讲这个问题。
在1-2次任务中,形式和所需存储的内容仍是相对单一的,第一次任务每一个项能够写成 a*x^b 的形式,也就是说咱们能够只存储a和b 便可。而第二次任务中,每一个项能够写成“a*x^b*sin(x)^c*cos(x)^d”的形式。那么咱们须要存储a,b,c,d便可。咱们只须要一次取一项,而后提取出对应的参数,而后按照规则求导,而后将参数组返回,这样能够完成求导。
在第三次任务中,形式变得至关的复杂,三角函数中能够塞入项,函数相互嵌套等状况,从而让咱们不能用有限的参数表示一个项。上面的方法已经不适用了。
因此在求导时只能作这样的处理:咱们按求导类型,分为expression,item,factor。expression能够由多个item加减得到,每一个item能够由factor相乘得到。每一个factor由三角函数,幂函数,常数,或者嵌套函数(函数+factor)组成。每个类别都向上一层传递本身读了字符串的什么内容,本身对这段内容的求导结果是什么。每一层在接受本身的下一层传输的信息的同时,也要对信息按照规则进行整合。在最底层的factor中对sin、cos、幂函数应该有本质性的处理方式(好比sin->cos之类的)。
2、程序分析
(1)基于度量来分析本身的程序结构
废话很少说,直接上三次做业的度量数据以及类图。
①OO度量数据(使用插件MetricsReloaded)
重要符号意义说明:
P1
LOC | NCLOC | |
Entry | 90 | 85 |
Main | 10 | 5 |
PolyDerivate | 239 | 217 |
P2
LOC | NCLOC | |
Entry | 96 | 86 |
Main | 10 | 5 |
Poly | 330 | 288 |
Term | 156 | 146 |
P3
LOC | NCLOC | |
Compact | 14 | 11 |
Entry | 28 | 24 |
Expression | 32 | 32 |
Factor | 181 | 170 |
Filter | 86 | 77 |
Item |
115 | 108 |
Main | 14 | 14 |
Reader | 88 | 83 |
②类图(使用工具是intellij(旗舰版)自带的diagram)
P1
P2
P3
缺点:其实很容易看出来,每一次做业的后半部分都有很是大的改动,主要是本身的程序并无考虑那么复杂的应用,也就是须要什么就写什么。在后面的任务中,几乎要所有重构。
优势:在最前面,Main后面一直是调用Entry。这里的Entry是用与放置不一样的使用模式(release,debug,batch_test)。在进行测试的时候大大的方便了本身。
(2)分析本身程序的bug
说实话,本身写出了很多的bug,主要的缘由是没有进行足够严格的测试。并且在一些细节问题上没有想清楚致使出现一些小错误,e.g.正负号写反,没有考虑0之类的。
我总结了一下,我犯的错误不少都是在细节实现时反复更改实现方式,从而致使在更改实现方式时,另一部分的代码的处理结果与另外一部分代码须要的函数输入不匹配,致使bug出现。
(3)分析本身发现别人程序bug所采用的策略
虽然我没有参加互测,可是我仍是想聊一聊bug查找的一些bug的方法(白盒和黑盒测试)。
白盒测试:是经过程序的源代码进行测试而不使用用户界面。这种类型的测试须要从代码句法发现内部代码在算法,溢出,路径,条件等等中的缺点或者错误,进而加以修正。
这个须要你去逐行阅读代码,同时,要尝试设计测试样例去覆盖程序中的全部的分支。并且你也能够顺便检查一下代码逻辑。
黑盒测试:是经过使用整个软件或某种软件功能来严格地测试, 而并无经过检查程序的源代码或者很清楚地了解该软件的源代码程序具体是怎样设计的。
直白来讲就是,就是知道已有的需求限制,划分等价类进行测试的方法。e.g. 若是只容许输入0-100的数字,那么我么能够划分为如下等价类:非法字符输入;<0; >100; 0-50; 50-100 共5个类型进行测试。对于具体的问题须要具体分析。这能够在宏观层面上发现迅速发现bug,而不须要阅读任何代码。
(4)Applying Creational Pattern
在个人观点看来,助教第1、第二次的目的达到了:让咱们习惯面向对象的方法和面向对象的程序编写。
可是第三次的题目,目的应该没有达到:使用继承和接口。在此次做业中,更加核心的东西应该是(文法分析,单例化等)。3个类之间除了2个private变量名和3个函数名相同以外,几乎没有什么共同之处。不管是解析、求导、化简都不同,在此次做业中继承和借口的使用的急迫程度依旧不存在。