OO 第一单元总结
第一次作业
题目要求
对表达式进行去括号。表达式由若干个项以加减号连接,项由若干个因子以乘号连接,因子仅包括带符号整数、幂函数和带括号的表达式,不会出现括号的嵌套。
设计思路
参考training的思路,首先建立Expression、Term、SignedInteger、PowerFunction类和Factor接口用于存储表达式。建立lexer类和parser类解析表达式。其中lexer对输入进行分析,调用toNextThing方法时,lexer将输入中下一个最小单元(如加号、连续两个乘号、x等)及其类型存储在lexer中。parser中的parseExpression、parseTerm、parseFactor三个方法根据lexer的分析结果将表达式存入一个Expression类中。
接下来是对表达式的化简。在Expression类中加入multiply方法,对每一种因子进行一次重载,在每一个项中,用一个新的Expression依次乘上向中的所有因子,就完成了去括号。
最后,为使输出的表达式尽可能最短,进行优化。将StandardTerm按幂排列,合并幂相同的项,若第一项系数为负,则找到系数为正的项代替之。
架构分析
Lexer:将输入分成最小单元。
Parser:对Lexer的分析结果进一步解析,将解析后的表达式存入一个Expression中。
Expression、Term、Factor、SignedInteger、PowerFunction:按照形式化表述建立的类或接口,用于存储相应结构。
StandardExpression、StandardTerm:为便于化简和输出建立的类。
从后续作业的迭代过程中来看,本次作业的架构比较清晰,容易迭代。
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
Lexer.Lexer(String) | 0 | 1 | 1 | 1 |
Lexer.getNextThing() | 0 | 1 | 1 | 1 |
Lexer.getNextType() | 0 | 1 | 1 | 1 |
Lexer.hasNextThing() | 0 | 1 | 1 | 1 |
Lexer.nextNumber() | 3 | 3 | 3 | 3 |
Lexer.reset() | 0 | 1 | 1 | 1 |
Lexer.skipBlank() | 2 | 1 | 2 | 3 |
Lexer.toNextThing(char) | 12 | 10 | 9 | 11 |
MainClass.main(String[]) | 0 | 1 | 1 | 1 |
Parser.Parser(Lexer) | 0 | 1 | 1 | 1 |
Parser.parseExpression() | 3 | 1 | 3 | 3 |
Parser.parseFactor() | 8 | 5 | 6 | 6 |
Parser.parseTerm(char) | 3 | 1 | 3 | 3 |
expression.Expression.Expression() | 0 | 1 | 1 | 1 |
expression.Expression.addTerm(Term) | 0 | 1 | 1 | 1 |
expression.Expression.getExponent() | 0 | 1 | 1 | 1 |
expression.Expression.getTerms() | 0 | 1 | 1 | 1 |
expression.Expression.multiply(Expression) | 15 | 3 | 9 | 9 |
expression.Expression.multiply(PowerFunction) | 4 | 1 | 3 | 3 |
expression.Expression.multiply(SignedInteger) | 4 | 1 | 3 | 3 |
expression.Expression.preTreat() | 1 | 1 | 2 | 2 |
expression.Expression.print() | 2 | 1 | 3 | 3 |
expression.Expression.removeBrackets() | 1 | 1 | 2 | 2 |
expression.Expression.setExponent(int) | 0 | 1 | 1 | 1 |
expression.PowerFunction.PowerFunction(int) | 0 | 1 | 1 | 1 |
expression.PowerFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.PowerFunction.print() | 0 | 1 | 1 | 1 |
expression.SignedInteger.SignedInteger(BigInteger) | 0 | 1 | 1 | 1 |
expression.SignedInteger.getNumber() | 0 | 1 | 1 | 1 |
expression.SignedInteger.print() | 0 | 1 | 1 | 1 |
expression.StandardExpression.StandardExpression(Expression) | 3 | 1 | 3 | 3 |
expression.StandardExpression.merge() | 14 | 4 | 7 | 8 |
expression.StandardExpression.print() | 4 | 1 | 3 | 3 |
expression.StandardExpression.putPositiveTermAhead() | 4 | 3 | 3 | 4 |
expression.StandardTerm.StandardTerm(Term) | 4 | 1 | 4 | 4 |
expression.StandardTerm.compareTo(StandardTerm) | 0 | 1 | 1 | 1 |
expression.StandardTerm.getExponent() | 0 | 1 | 1 | 1 |
expression.StandardTerm.getFactor() | 0 | 1 | 1 | 1 |
expression.StandardTerm.merge(StandardTerm) | 1 | 1 | 2 | 2 |
expression.StandardTerm.print(boolean) | 20 | 1 | 14 | 14 |
expression.Term.Term() | 0 | 1 | 1 | 1 |
expression.Term.addFactor(Factor) | 0 | 1 | 1 | 1 |
expression.Term.getFactors() | 0 | 1 | 1 | 1 |
expression.Term.preTreat() | 4 | 1 | 4 | 4 |
expression.Term.print() | 1 | 1 | 2 | 2 |
expression.Term.removeBrackets() | 8 | 1 | 5 | 5 |
expression.Term.setSign(char, char) | 1 | 1 | 1 | 2 |
Class | OCavg | OCmax | WMC |
---|---|---|---|
Lexer | 2.5 | 10 | 20 |
MainClass | 1 | 1 | 1 |
Parser | 3.25 | 6 | 13 |
expression.Expression | 2.45 | 9 | 27 |
expression.PowerFunction | 1 | 1 | 3 |
expression.SignedInteger | 1 | 1 | 3 |
expression.StandardExpression | 4.5 | 8 | 18 |
expression.StandardTerm | 3.67 | 13 | 22 |
expression.Term | 2.29 | 5 | 16 |
大部分方法的复杂度在可接受范围之内。复杂度较高的方法按复杂度高的原因分为以下两类:StandardTerm.print(boolean)、Lexer.toNextThing(char)、Parser.parseFactor()等,因为这些方法需要处理的情况比较多,包含大量的if,且解析因子时,需要解析三种不同的因子,情况复杂。expression.StandardExpression.merge(),这个方法进行合并同类项时需要进行两层循环。
包含以上方法的Lexer、StandardExpression、StandardTerm等类复杂度较高。
缺点
-
输出时,StandardExpression等类直接用System.out.print()输出,而不是用toString方法。在需要向文件输出等情况下,修改难度大,不便于相关操作。
-
对表达式进行化简时,先将表达式去括号,后合并同类项。在一些情况下,会导致运行时间极长,如:(1+1+1+1+1)**8,这一组数据程序运行了20分钟都没有输出结果。
Bug分析
本次作业中,我在强和互测中均没有出现bug,并在互测中成功地发现了一个别人的bug。
在与同学对拍的过程中发现了一个bug:由于lexer读入一个加号或减号,这个加号或减号可能属于带符号整数的一部分,需要传入一个参数告知lexer是否应该继续向下读接下来的数字。在Parser.parseFactor()方法中由于少考虑了一种情况,当带指数的表达式后出现加减号时,此加减号及后面的部分全部无法读入。出现bug的方法是一个复杂度较高的方法,需要考虑的情况比较多,就更容易出现失误。
在互测中,我用python编写了一个简单的生成测试数据和检查正确性的程序。用random库生成随机数,用sympy库化简表达式并检查正确性。并没有结合被测程序的代码设计结构来设计测试用例,只是用随机生成的测试数据测试。
第二次作业
题目要求
在上一次作业的基础上,加入了正弦、余弦、自定义函数、求和函数四种因子。
设计思路
对正弦、余弦两种三角函数分别建立类,按照类似处理带符号整数和幂函数的方法处理。对于自定义函数,定义函数类,将函数等号右侧的部分以字符串形式存储。在解析中遇到自定义函数调用时,将参数替换为实参。再用一个新的parser解析即可。对于求和函数,将待求和项以字符串形式存储,并替换其中的i,Parser在处理自定义函数调用和求和函数时,相关方法直接返回一个Expression。
由于字符串替换会在处理一些情况时出现问题,如:sum(i, -5, -1, i**2) ,需要在替换时加上括号,可能产生多层括号,顺便解决了处理多层括号的问题。
对第一作业中合并同类项的时机进行了修改。修改后只要出现项之间的加法就会进行一次合并同列项。上一次运行时间极长的测试数据,现在可以立即输出结果。
第一次作业中print()方法全部改为toString()方法,返回字符串。
架构分析
Function:用于存储函数定义。
Variable:用于存储函数中自变量。
SineFunction和CosineFunction:按照形式化表述建立的类,用于存储正弦和余弦函数。
本次作业的架构对第三次作业的迭代非常方便。
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
Lexer.Lexer() | 0 | 1 | 1 | 1 |
Lexer.getNext() | 0 | 1 | 1 | 1 |
Lexer.getNextType() | 0 | 1 | 1 | 1 |
Lexer.hasNext() | 0 | 1 | 1 | 1 |
Lexer.nextInBracketFactor() | 3 | 3 | 3 | 3 |
Lexer.nextNumber() | 3 | 3 | 3 | 3 |
Lexer.nextWord() | 3 | 3 | 3 | 3 |
Lexer.reset() | 0 | 1 | 1 | 1 |
Lexer.setInput(String) | 0 | 1 | 1 | 1 |
Lexer.skipBlank() | 2 | 1 | 2 | 3 |
Lexer.toNext(char) | 11 | 10 | 9 | 10 |
Lexer.toNext2(char) | 10 | 8 | 8 | 9 |
MainClass.main(String[]) | 1 | 1 | 2 | 2 |
Parser.Parser(Lexer) | 0 | 1 | 1 | 1 |
Parser.addFunction(Function) | 0 | 1 | 1 | 1 |
Parser.parseCosineFunction() | 2 | 1 | 2 | 2 |
Parser.parseExpression() | 3 | 1 | 3 | 3 |
Parser.parseFactor() | 9 | 8 | 9 | 9 |
Parser.parseFunction(String) | 1 | 1 | 2 | 2 |
Parser.parseFunctionDefinition() | 1 | 1 | 2 | 2 |
Parser.parsePowerFunction() | 2 | 2 | 2 | 2 |
Parser.parseSignedInteger() | 0 | 1 | 1 | 1 |
Parser.parseSineFunction() | 2 | 1 | 2 | 2 |
Parser.parseSumFunction() | 1 | 1 | 2 | 2 |
Parser.parseTerm(char) | 3 | 1 | 3 | 3 |
Parser.printFunctions() | 1 | 1 | 2 | 2 |
Parser.setLexerInput(String) | 0 | 1 | 1 | 1 |
expression.CosineFunction.CosineFunction(Factor) | 2 | 1 | 2 | 2 |
expression.CosineFunction.getContent() | 0 | 1 | 1 | 1 |
expression.CosineFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.CosineFunction.setExponent(int) | 0 | 1 | 1 | 1 |
expression.CosineFunction.toString() | 1 | 2 | 2 | 2 |
expression.Expression.Expression() | 0 | 1 | 1 | 1 |
expression.Expression.addTerm(Term) | 0 | 1 | 1 | 1 |
expression.Expression.expandAndMerge() | 12 | 1 | 9 | 9 |
expression.Expression.getExponent() | 0 | 1 | 1 | 1 |
expression.Expression.getTerm(int) | 0 | 1 | 1 | 1 |
expression.Expression.getTerms() | 0 | 1 | 1 | 1 |
expression.Expression.multiply(CosineFunction) | 4 | 1 | 3 | 3 |
expression.Expression.multiply(Expression) | 15 | 3 | 9 | 9 |
expression.Expression.multiply(PowerFunction) | 4 | 1 | 3 | 3 |
expression.Expression.multiply(SignedInteger) | 4 | 1 | 3 | 3 |
expression.Expression.multiply(SineFunction) | 4 | 1 | 3 | 3 |
expression.Expression.preTreat() | 1 | 1 | 2 | 2 |
expression.Expression.removeBrackets() | 1 | 1 | 2 | 2 |
expression.Expression.setExponent(int) | 0 | 1 | 1 | 1 |
expression.Expression.size() | 0 | 1 | 1 | 1 |
expression.Expression.toString() | 2 | 1 | 2 | 3 |
expression.Function.Function(String, ArrayList<Variable>, String) | 0 | 1 | 1 | 1 |
expression.Function.getContent() | 0 | 1 | 1 | 1 |
expression.Function.getName() | 0 | 1 | 1 | 1 |
expression.Function.getVariables() | 0 | 1 | 1 | 1 |
expression.Function.toString() | 1 | 1 | 2 | 2 |
expression.PowerFunction.PowerFunction(int) | 0 | 1 | 1 | 1 |
expression.PowerFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.PowerFunction.toString() | 2 | 3 | 1 | 3 |
expression.SignedInteger.SignedInteger(BigInteger) | 0 | 1 | 1 | 1 |
expression.SignedInteger.getNumber() | 0 | 1 | 1 | 1 |
expression.SignedInteger.toString() | 0 | 1 | 1 | 1 |
expression.SineFunction.SineFunction(Factor) | 2 | 1 | 2 | 2 |
expression.SineFunction.getContent() | 0 | 1 | 1 | 1 |
expression.SineFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.SineFunction.setExponent(int) | 0 | 1 | 1 | 1 |
expression.SineFunction.toString() | 1 | 2 | 2 | 2 |
expression.StandardExpression.StandardExpression() | 0 | 1 | 1 | 1 |
expression.StandardExpression.StandardExpression(int) | 0 | 1 | 1 | 1 |
expression.StandardExpression.add(StandardExpression) | 1 | 1 | 2 | 2 |
expression.StandardExpression.addTerm(StandardTerm) | 0 | 1 | 1 | 1 |
expression.StandardExpression.getTerms() | 0 | 1 | 1 | 1 |
expression.StandardExpression.merge() | 18 | 5 | 8 | 8 |
expression.StandardExpression.mergeTrigonometricFunctions() | 6 | 1 | 4 | 4 |
expression.StandardExpression.multiply(CosineFunction) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(Expression) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(PowerFunction) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(SignedInteger) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(SineFunction) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(StandardExpression) | 3 | 1 | 3 | 3 |
expression.StandardExpression.putPositiveTermAhead() | 4 | 3 | 3 | 4 |
expression.StandardExpression.toString() | 2 | 2 | 2 | 3 |
expression.StandardTerm.StandardTerm(int) | 0 | 1 | 1 | 1 |
expression.StandardTerm.compareTo(StandardTerm) | 0 | 1 | 1 | 1 |
expression.StandardTerm.equalsTo(StandardTerm) | 1 | 1 | 2 | 2 |
expression.StandardTerm.getExponent() | 0 | 1 | 1 | 1 |
expression.StandardTerm.getFactor() | 0 | 1 | 1 | 1 |
expression.StandardTerm.isInteger() | 1 | 1 | 3 | 3 |
expression.StandardTerm.merge(StandardTerm) | 0 | 1 | 1 | 1 |
expression.StandardTerm.mergeTrigonometricFunctions(StandardTerm) | 2 | 2 | 2 | 3 |
expression.StandardTerm.multiply(CosineFunction) | 6 | 4 | 5 | 6 |
expression.StandardTerm.multiply(PowerFunction) | 0 | 1 | 1 | 1 |
expression.StandardTerm.multiply(SignedInteger) | 0 | 1 | 1 | 1 |
expression.StandardTerm.multiply(SineFunction) | 6 | 4 | 5 | 6 |
expression.StandardTerm.multiply(StandardTerm) | 16 | 1 | 9 | 9 |
expression.StandardTerm.multiplyWithReturn(StandardTerm) | 0 | 1 | 1 | 1 |
expression.StandardTerm.setExponent(int) | 0 | 1 | 1 | 1 |
expression.StandardTerm.setFactor(BigInteger) | 0 | 1 | 1 | 1 |
expression.StandardTerm.similarTo(StandardTerm) | 21 | 12 | 7 | 14 |
expression.StandardTerm.toString(boolean, boolean) | 18 | 1 | 10 | 15 |
expression.Term.Term() | 0 | 1 | 1 | 1 |
expression.Term.addFactor(Factor) | 0 | 1 | 1 | 1 |
expression.Term.getFactor(int) | 0 | 1 | 1 | 1 |
expression.Term.getFactors() | 0 | 1 | 1 | 1 |
expression.Term.preTreat() | 4 | 1 | 4 | 4 |
expression.Term.removeBrackets() | 10 | 1 | 7 | 7 |
expression.Term.setSign(char, char) | 1 | 1 | 1 | 2 |
expression.Term.size() | 0 | 1 | 1 | 1 |
expression.Term.toString() | 1 | 1 | 2 | 2 |
expression.Variable.Variable(String) | 0 | 1 | 1 | 1 |
expression.Variable.getName() | 0 | 1 | 1 | 1 |
Class | OCavg | OCmax | WMC |
---|---|---|---|
Lexer | 2.92 | 10 | 35 |
MainClass | 2 | 2 | 2 |
Parser | 2.36 | 9 | 33 |
expression.CosineFunction | 1.4 | 2 | 7 |
expression.Expression | 2.75 | 9 | 44 |
expression.Function | 1.2 | 2 | 6 |
expression.PowerFunction | 1.67 | 3 | 5 |
expression.SignedInteger | 1 | 1 | 3 |
expression.SineFunction | 1.4 | 2 | 7 |
expression.StandardExpression | 2.53 | 8 | 38 |
expression.StandardTerm | 3.22 | 12 | 58 |
expression.Term | 2.22 | 7 | 20 |
expression.Variable | 1 | 1 | 2 |
expression.Expression.expandAndMerge()等方法需要进行双层遍历和调用其他方法,expression.StandardTerm.similarTo(StandardTerm)等方法需要进行遍历和查找以及与其他方法的互相调用,expression.StandardTerm.toString(boolean, boolean)等方法需要考虑的情况很多,所以这些方法的各种复杂度都比较高。
缺点
-
expression.StandardExpression.merge()方法各种复杂度高,且使用次数较多。
-
对自定义函数和求和函数使用了字符串替换的方法,容易出现问题,在第三次作业内容未知的情况下比较危险。
-
StandardTerm类中用HashMap存储三角函数,key为三角函数括号内的因子,value为指数。但实际使用效果不能体现HashMap的优势,不如新建类。
-
StandardExpression等类名、方法名、变量名过长,代码观感差。
Bug分析
本次作业中出现了一个极其致命的bug,若三角函数中有正负号,则无法读取正负号及其之后的所有内容,与上一次作业中的bug是同一个原因。
对于找其他人的bug,仍然采取了用python随机生成数据加评测的方法,但没有成功。
第三次作业
题目要求
本次作业加入了多层括号嵌套、三角函数嵌套表达式、自定义函数嵌套。
设计思路
多层括号嵌套已在第二次作业中解决,自定义函数嵌套只需要将解析整个表达式的parser中存储的函数传给解析解析自定义函数调用的parser就可解决。对于三角函数嵌套表达式,新建了StandardSineFunction和StandardCosineFunction两个类用于存储化简合并后的正弦和余弦。
对合并同类项的方法和时机再次优化,新的合并同类项方法仅在向表达式中加入新项时检查新项是否能与原有的某个项合并。
架构分析
本次作业的架构比上一次更加复杂,但还算清晰。部分类中方法数过多。
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
Lexer.Lexer() | 0 | 1 | 1 | 1 |
Lexer.getNext() | 0 | 1 | 1 | 1 |
Lexer.getNextType() | 0 | 1 | 1 | 1 |
Lexer.hasNext() | 0 | 1 | 1 | 1 |
Lexer.nextInBracketFactor() | 4 | 1 | 3 | 4 |
Lexer.nextNumber() | 3 | 3 | 3 | 3 |
Lexer.nextWord() | 3 | 3 | 3 | 3 |
Lexer.reset() | 0 | 1 | 1 | 1 |
Lexer.setInput(String) | 0 | 1 | 1 | 1 |
Lexer.skipBlank() | 2 | 1 | 2 | 3 |
Lexer.toNext(char) | 11 | 10 | 9 | 10 |
Lexer.toNext2(char) | 10 | 8 | 8 | 9 |
MainClass.main(String[]) | 1 | 1 | 2 | 2 |
Parser.Parser(Lexer) | 0 | 1 | 1 | 1 |
Parser.addFunction(Function) | 0 | 1 | 1 | 1 |
Parser.parseCosineFunction() | 2 | 1 | 2 | 2 |
Parser.parseExpression() | 3 | 1 | 3 | 3 |
Parser.parseFactor() | 9 | 8 | 9 | 9 |
Parser.parseFunction(String) | 2 | 1 | 3 | 3 |
Parser.parseFunctionDefinition() | 1 | 1 | 2 | 2 |
Parser.parsePowerFunction() | 2 | 2 | 2 | 2 |
Parser.parseSignedInteger() | 0 | 1 | 1 | 1 |
Parser.parseSineFunction() | 2 | 1 | 2 | 2 |
Parser.parseSumFunction() | 1 | 1 | 2 | 2 |
Parser.parseTerm(char) | 3 | 1 | 3 | 3 |
Parser.printFunctions() | 1 | 1 | 2 | 2 |
Parser.setLexerInput(String) | 0 | 1 | 1 | 1 |
expression.CosineFunction.CosineFunction(Expression) | 0 | 1 | 1 | 1 |
expression.CosineFunction.getContent() | 0 | 1 | 1 | 1 |
expression.CosineFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.CosineFunction.setExponent(BigInteger) | 0 | 1 | 1 | 1 |
expression.CosineFunction.toString() | 1 | 2 | 2 | 2 |
expression.Expression.Expression() | 0 | 1 | 1 | 1 |
expression.Expression.addTerm(Term) | 0 | 1 | 1 | 1 |
expression.Expression.expandAndMerge() | 10 | 1 | 8 | 8 |
expression.Expression.getExponent() | 0 | 1 | 1 | 1 |
expression.Expression.getTerm(int) | 0 | 1 | 1 | 1 |
expression.Expression.getTerms() | 0 | 1 | 1 | 1 |
expression.Expression.preTreat() | 1 | 1 | 2 | 2 |
expression.Expression.setExponent(int) | 0 | 1 | 1 | 1 |
expression.Expression.size() | 0 | 1 | 1 | 1 |
expression.Expression.toString() | 2 | 1 | 2 | 3 |
expression.Function.Function(String, ArrayList<Variable>, String) | 0 | 1 | 1 | 1 |
expression.Function.getContent() | 0 | 1 | 1 | 1 |
expression.Function.getName() | 0 | 1 | 1 | 1 |
expression.Function.getVariables() | 0 | 1 | 1 | 1 |
expression.Function.toString() | 1 | 1 | 2 | 2 |
expression.PowerFunction.PowerFunction(BigInteger) | 0 | 1 | 1 | 1 |
expression.PowerFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.PowerFunction.toString() | 2 | 3 | 1 | 3 |
expression.SignedInteger.SignedInteger(BigInteger) | 0 | 1 | 1 | 1 |
expression.SignedInteger.getNumber() | 0 | 1 | 1 | 1 |
expression.SignedInteger.toString() | 0 | 1 | 1 | 1 |
expression.SineFunction.SineFunction(Expression) | 0 | 1 | 1 | 1 |
expression.SineFunction.getContent() | 0 | 1 | 1 | 1 |
expression.SineFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.SineFunction.setExponent(BigInteger) | 0 | 1 | 1 | 1 |
expression.SineFunction.toString() | 1 | 2 | 2 | 2 |
expression.StandardCosineFunction.StandardCosineFunction() | 0 | 1 | 1 | 1 |
expression.StandardCosineFunction.StandardCosineFunction(CosineFunction) | 0 | 1 | 1 | 1 |
expression.StandardCosineFunction.copy() | 0 | 1 | 1 | 1 |
expression.StandardCosineFunction.equalsTo(StandardCosineFunction) | 1 | 1 | 2 | 2 |
expression.StandardCosineFunction.getContent() | 0 | 1 | 1 | 1 |
expression.StandardCosineFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.StandardCosineFunction.setExponent(BigInteger) | 0 | 1 | 1 | 1 |
expression.StandardCosineFunction.similarTo(StandardCosineFunction) | 0 | 1 | 1 | 1 |
expression.StandardCosineFunction.toString() | 3 | 1 | 1 | 4 |
expression.StandardExpression.StandardExpression() | 0 | 1 | 1 | 1 |
expression.StandardExpression.StandardExpression(int) | 0 | 1 | 1 | 1 |
expression.StandardExpression.add(StandardExpression) | 1 | 1 | 2 | 2 |
expression.StandardExpression.addTerm(StandardTerm) | 0 | 1 | 1 | 1 |
expression.StandardExpression.copy() | 1 | 1 | 2 | 2 |
expression.StandardExpression.equalsTo(StandardExpression) | 9 | 6 | 3 | 6 |
expression.StandardExpression.equalsZero() | 1 | 1 | 2 | 2 |
expression.StandardExpression.getTerms() | 0 | 1 | 1 | 1 |
expression.StandardExpression.isSimpleFactor() | 1 | 1 | 2 | 2 |
expression.StandardExpression.merge() | 18 | 5 | 8 | 8 |
expression.StandardExpression.mergeBettered() | 8 | 4 | 5 | 6 |
expression.StandardExpression.mergeTrigonometricFunctions() | 6 | 1 | 4 | 4 |
expression.StandardExpression.multiply(CosineFunction) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(Expression) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(PowerFunction) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(SignedInteger) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(SineFunction) | 1 | 1 | 2 | 2 |
expression.StandardExpression.multiply(StandardExpression) | 3 | 1 | 3 | 3 |
expression.StandardExpression.putPositiveTermAhead() | 5 | 3 | 4 | 5 |
expression.StandardExpression.toString(boolean) | 2 | 2 | 2 | 3 |
expression.StandardSineFunction.StandardSineFunction() | 0 | 1 | 1 | 1 |
expression.StandardSineFunction.StandardSineFunction(SineFunction) | 0 | 1 | 1 | 1 |
expression.StandardSineFunction.copy() | 0 | 1 | 1 | 1 |
expression.StandardSineFunction.equalsTo(StandardSineFunction) | 1 | 1 | 2 | 2 |
expression.StandardSineFunction.getContent() | 0 | 1 | 1 | 1 |
expression.StandardSineFunction.getExponent() | 0 | 1 | 1 | 1 |
expression.StandardSineFunction.setExponent(BigInteger) | 0 | 1 | 1 | 1 |
expression.StandardSineFunction.similarTo(StandardSineFunction) | 0 | 1 | 1 | 1 |
expression.StandardSineFunction.toString() | 3 | 1 | 1 | 4 |
expression.StandardTerm.StandardTerm(int) | 0 | 1 | 1 | 1 |
expression.StandardTerm.addCosineFunction(StandardCosineFunction) | 0 | 1 | 1 | 1 |
expression.StandardTerm.addSineFunction(StandardSineFunction) | 0 | 1 | 1 | 1 |
expression.StandardTerm.copy() | 2 | 1 | 3 | 3 |
expression.StandardTerm.equalsTo(StandardTerm) | 1 | 1 | 2 | 2 |
expression.StandardTerm.equalsZero() | 0 | 1 | 1 | 1 |
expression.StandardTerm.getExponent() | 0 | 1 | 1 | 1 |
expression.StandardTerm.getFactor() | 0 | 1 | 1 | 1 |
expression.StandardTerm.isCosineFunction() | 1 | 1 | 4 | 4 |
expression.StandardTerm.isInteger() | 1 | 1 | 3 | 3 |
expression.StandardTerm.isPowerFunction() | 1 | 1 | 3 | 3 |
expression.StandardTerm.isSimpleFactor() | 1 | 1 | 4 | 4 |
expression.StandardTerm.isSineFunction() | 1 | 1 | 4 | 4 |
expression.StandardTerm.merge(StandardTerm) | 0 | 1 | 1 | 1 |
expression.StandardTerm.mergeTrigonometricFunctions(StandardTerm) | 2 | 2 | 2 | 3 |
expression.StandardTerm.multiply(CosineFunction) | 1 | 2 | 1 | 2 |
expression.StandardTerm.multiply(PowerFunction) | 0 | 1 | 1 | 1 |
expression.StandardTerm.multiply(SignedInteger) | 0 | 1 | 1 | 1 |
expression.StandardTerm.multiply(SineFunction) | 1 | 2 | 1 | 2 |
expression.StandardTerm.multiply(StandardCosineFunction) | 4 | 4 | 3 | 4 |
expression.StandardTerm.multiply(StandardSineFunction) | 4 | 4 | 4 | 4 |
expression.StandardTerm.multiply(StandardTerm) | 2 | 1 | 3 | 3 |
expression.StandardTerm.multiplyWithReturn(StandardTerm) | 0 | 1 | 1 | 1 |
expression.StandardTerm.putPositiveAhead() | 2 | 1 | 3 | 3 |
expression.StandardTerm.setExponent(BigInteger) | 0 | 1 | 1 | 1 |
expression.StandardTerm.setFactor(BigInteger) | 0 | 1 | 1 | 1 |
expression.StandardTerm.similarTo(StandardTerm) | 19 | 12 | 5 | 12 |
expression.StandardTerm.toString(boolean, boolean) | 14 | 1 | 11 | 13 |
expression.Term.Term() | 0 | 1 | 1 | 1 |
expression.Term.addFactor(Factor) | 0 | 1 | 1 | 1 |
expression.Term.getFactor(int) | 0 | 1 | 1 | 1 |
expression.Term.getFactors() | 0 | 1 | 1 | 1 |
expression.Term.preTreat() | 6 | 1 | 6 | 6 |
expression.Term.setSign(char, char) | 1 | 1 | 1 | 2 |
expression.Term.size() | 0 | 1 | 1 | 1 |
expression.Term.toString() | 1 | 1 | 2 | 2 |
expression.Variable.Variable(String) | 0 | 1 | 1 | 1 |
expression.Variable.getName() | 0 | 1 | 1 | 1 |
Class | OCavg | OCmax | WMC |
---|---|---|---|
Lexer | 3 | 10 | 36 |
MainClass | 2 | 2 | 2 |
Parser | 2.43 | 9 | 34 |
expression.CosineFunction | 1.2 | 2 | 6 |
expression.Expression | 2 | 8 | 20 |
expression.Function | 1.2 | 2 | 6 |
expression.PowerFunction | 1.67 | 3 | 5 |
expression.SignedInteger | 1 | 1 | 3 |
expression.SineFunction | 1.2 | 2 | 6 |
expression.StandardCosineFunction | 1.33 | 4 | 12 |
expression.StandardExpression | 2.75 | 8 | 55 |
expression.StandardSineFunction | 1.33 | 4 | 12 |
expression.StandardTerm | 2.21 | 12 | 62 |
expression.Term | 1.88 | 6 | 15 |
expression.Variable | 1 | 1 | 2 |
本次作业中复杂度大的方法与上一次作业基本相同。
对于复杂度较大的expression.StandardExpression.merge()方法,在其多数使用情况下改为使用复杂度较小的expression.StandardExpression.mergeBettered()方法。
缺点
-
expression.StandardTerm.similarTo(StandardTerm)等需要经常使用的方法复杂度过高。
-
几乎没有做优化。
Bug分析
本次作业中,我的程序在强测和互测中没有出现bug。在中测中,发现一个有关深拷贝的bug:对于类似(sin(x))**3的测试数据,在用一个StandardExpression乘以(sin(x))**3时,是将同一个sin(x)乘了三次。每一次乘都会改变sin(x)中内容的状态。为了解决这个bug,对StandardSineFunction等4个类增加了copy()方法,解决了上述bug。
互测中,我没有继续使用随机生成的测试数据hack别人的程序,而是使用一些容易出错的共性问题,如sum函数中s和e超过int型上限,0**0,三角函数中表达式格式错误等,并成功找到了5次,其中共4个不同的bug。
体会