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;}
    

     

    1.5 解析 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!

 

 

posted @ 2022-03-24 20:43  KeiEswy  阅读(76)  评论(5编辑  收藏  举报