BUAA_OO 第一单元总结
1.结构
1.1 大体思路
- 建立Term,Expression分别表示项和表达式;
- 建立Lexer,Parser解析表达式;
1.2 项 Term
- 笔者将项处理成形如axb∏sin(expi)cos(expi)
- axb :a--constant;b--exponent;
- ∏sin(expi)cos(expi):parameter整型数组存储三角函数类型,expression表达式数组存储参与三角运算的表达式
-
public class Term { private BigInteger constant; private BigInteger exponent; private ArrayList<Integer> parameter = new ArrayList<Integer>(); private ArrayList<Expression> expression = new ArrayList<Expression>(); }
1.3 表达式 Expression
- 笔者将表达式处理成∑termi形式,通过Term类数组存储各个项
-
public class Expression { private ArrayList<Term> expression = new ArrayList<>();}
1.4 词法分析 Lexer
- 笔者认为可将每一次运算简化成 expi?/num? [+/-/*/**/sin/cos] expi/num?
- 建立lexer处理运算表达式expi,运算数num,运算符
- 处理运算表达式:构建String类expression1和expression2存储表达式,作为hashmap的key,并传入Parser进一步解析
- 处理运算数:笔者在此模块将运算数与表达式视作一类,存储入expression1和expression2中,传入Parser进一步解析
- 处理运算符:笔者将运算细分成取反(neg),正弦(sin),余弦(cos),加(add),减(sub),乘(*),乘方(**),取正(pos);将八类运算按Lexer-Parser运算符表解析,用整形parser表示,传入Parser进一步解析
-
运算 parser值 neg 1 sin 2 cos 3 add 4 sub 5 mul 6 pow 7 pos 8 -
public class Lexer { private String curline; private String name; private String expression1 = "1"; private String expression2 = "1"; private int parser;}
- 建立hashmap<String,Expression>,以Lexer传入的expression1,expression2为key,以解析表达式类作为value
- 通过Lexer传入的整形lexer进行表达式或数的运算
-
public class Parser { private Lexer lexer; private HashMap<String, Expression> map; public Parser(Lexer lexer, HashMap<String, Expression> map) { this.lexer = lexer; this.map = map; }
2.算法
2.1 大体思路
- 逐层运算:将表达式之间的复杂运算逐层解析成项之间的简单运算
2.2 表达式运算
- 笔者将表达式的运算分成:加(add),减(sub),乘(*),乘方(**),正弦(sin),余弦(cos)六类
- 加(add):由于笔者以Term数组表示表达式,故表达式的相加可通过Term数组相加实现,在此不再赘述
- 减(sub):需要将作为减数的表达式取反,可通过将Term数组中的所有Term取反实现,其余与加法相同
- 乘(*):需要遍历表达式的Term数组,将表达式乘法转化成若干Term相乘,最后将结果相加
- 乘方(**):可视作若干次表达式与自身的乘法,不再赘述
- 正弦/余弦(sin/cos):表达式进行该运算后降级为Term类,存储入新建Term的三角部分
2.3 解析方式
- 通过整形parser值来表示运算方式,parser值在Term,Expression,Lexer,Parser类内通用
- 笔者将运算细分成表达式之间,运算数之间,表达式与数之间三种情况。在解析前先判断Lexer传入的String类表示为expi或num
2.4 项运算
- 笔者将项的运算分成:加(add),减(mul),乘(*),乘方(**),取反(neg),取正(pos),正弦(sin),余弦(cos)
- 由于项的运算相对简单,笔者不再赘述
3.细节
3.1 UML类图
3.2 度量分析
可以看出,在Parser类的next()复杂度过高,原因是该函数是解析表达式的主函数。所以笔者的解析方式并不巧妙,以后会尽量改进优化。
3.3 化简
笔者对于化简的做法较为简单,仅实现了表达式的合并同类项,sin0=0,cos0=1,对于二倍角公式,sin2x+cos2x=1等三角恒等式没有过多涉及,以后会尽量改进优化
3.4 bug修复
笔者在评测过程中遇到了一下bug:
-
-
- Term的系数constant的数据类型过小(Integer),计算时容易出现溢出,后改为BigInteger解决
- 程序无法处理形如sin(1)的项,后发现将1等运算数视为项导致出错,应将其视作表达式
- 计算乘方时没有考虑0次方情况,导致出错
- 程序无法处理形如+1,+x等表达式,后发现java内置函数无法将其直接转化,应特判正号
-
4.总结
在本单元oo作业中,笔者深刻理解了面向对象的理念,并且深入熟悉了java语言,希望在以后的学习过程中可以不断进步,少些bug!