表达式解析和表达式求导
Differential Homework
形式化描述
对表达式做求导
设定的形式化表述
- 表达式 空白项 [加减 空白项] 项 空白项 | 表达式 加减 空白项 项 空白项
- 项 [加减 空白项] 因子 | 项 空白项 * 空白项 因子
- 因子 变量因子 | 常数因子
- 变量因子 幂函数 | 三角函数
- 常数因子 带符号的整数
- 幂函数 x [空白项 指数]
- 三角函数 sin 空白项 ‘(’ 空白项 x 空白项 ‘)’ [空白项 指数] | cos 空白项 ‘(’ 空白项 x 空白项 ‘)’ [空白项 指数]
- 指数 ** 空白项 带符号的整数
- 带符号的整数 [加减] 允许前导零的整数
- 允许前导零的整数 (0|1|2|…|9){0|1|2|…|9}
- 空白字符
(空格) |
\t
- 空白项 {空白字符}
- 加减 + | -
其中{}表示0个、1个或多个,[]表示0个或1个,|表示多个之中选择。
式子的具体含义参照其数学含义。
核心思路
- 解析表达式,建立表达式树,返回表达式树的根节点。
- 遍历表达式,生成求导树
- 输出求导树
文法分析
num = [+-] \d+
power = ( x | sin(factor) | cos(factor) ) [^ num]?
factor = power | (expr) | num
term =
[+-] factor |
term * factor
expr =
[+-] term |
expr [+-] term
- 符号节点
+
, 有多个孩子,表示他们相加,其实质表示一个表达式(因子) - 符号节点
*
, 有多个孩子,表示他们相乘,其实质表示一个项 - 符号节点
sin()
,cos()
, 有一个孩子,表示对其做三角函数运算,其实质表示三角函数因子和嵌套因子,其孩子只能是因子 - 值节点
num
- 值节点
节点情形
子节点 : 1,3,4,5
化简操作
对于power节点,可以化简所有对deg
为0的求导操作。
对于Mul节点,可以吸收所有同级别的
合格的parser如下
import java.math.BigInteger;
import java.util.Scanner;
public class Myinput {
private static Scanner sc;
private static String line;
private static int cursor;
private static final BigInteger deglim = BigInteger.valueOf(10000);
public Myinput() {
line = "";
cursor = 0;
}
public Cal input() throws Exception {
sc = new Scanner(System.in);
if (sc.hasNext()) {
line = sc.nextLine();
} else {
throw new Exception("Empty file");
}
cursor = 0;
return parseExpr();
}
// signal function
private boolean isspace(char ch) { return (ch == '\t' || ch == ' '); }
private boolean isdigit(char ch) { return (ch >= '0' && ch <= '9'); }
private boolean issign(char ch) { return (ch == '+' || ch == '-'); }
// char function
private boolean hasNext() { return cursor < line.length(); }
private char peak() throws Exception {
if (hasNext()) {
return line.charAt(cursor);
}
else {
throw new Exception("No more char");
}
}
private char pop() throws Exception {
if (hasNext()) {
return line.charAt(cursor++);
}
else {
throw new Exception("No more char");
}
}
private boolean jumpspace() throws Exception {
boolean ret = false;
while (hasNext() && isspace(peak())) {
ret = true;
pop();
}
return ret;
}
private void has(char c) throws Exception {
char now = pop();
if (now != c) {
throw new Exception("Not fixed " + c + " but " + now);
}
}
// parse functino
public int parseSign() throws Exception {
char now = pop();
if (now == '+') {
return 1;
}
else if (now == '-') {
return -1;
}
else {
throw new Exception("Not a sign");
}
}
public BigInteger parseNum() throws Exception {
char now = peak();
int start = cursor;
int end = start;
if (issign(now)) {
pop();
}
if (!isdigit(peak())) {
throw new Exception("Not a number");
}
while (hasNext() && isdigit(peak())) {
pop();
end = cursor;
}
return new BigInteger(line.substring(start,end));
}
public Cal parseSin() throws Exception {
jumpspace();
has('s');
has('i');
has('n');
jumpspace();
has('(');
jumpspace();
final Cal sin = parseFactor();
jumpspace();
has(')');
jumpspace();
BigInteger deg = BigInteger.ONE;
if (hasNext() && peak() == '^') {
pop();
jumpspace();
deg = parseNum();
if (deg.abs().compareTo(deglim) > 0) {
throw new Exception("degree limit for Sin");
}
}
return new Sin(sin,deg);
}
public Cal parseCos() throws Exception {
jumpspace();
has('c');
has('o');
has('s');
jumpspace();
has('(');
jumpspace();
final Cal cos = parseFactor();
jumpspace();
has(')');
jumpspace();
BigInteger deg = BigInteger.ONE;
if (hasNext() && peak() == '^') {
pop();
jumpspace();
deg = parseNum();
if (deg.abs().compareTo(deglim) > 0) {
throw new Exception("degree limit for Cos");
}
}
return new Cos(cos,deg);
}
public Cal parsePower() throws Exception {
jumpspace();
has('x');
jumpspace();
BigInteger deg = BigInteger.ONE;
if (hasNext() && peak() == '^') {
pop();
jumpspace();
deg = parseNum();
if (deg.abs().compareTo(deglim) > 0) {
throw new Exception("degree limit for Power");
}
}
return new Pow(deg);
}
public Cal parseFactor() throws Exception {
jumpspace();
char now = peak();
Cal ret = null;
if (issign(now) || isdigit(now)) { // number
ret = new Val(parseNum());
}
else if (now == 'x') { // x power
ret = parsePower();
}
else if (now == 's') { // sin power
ret = parseSin();
}
else if (now == 'c') { // cos power
ret = parseCos();
}
else if (now == '(') {
has('(');
ret = parseExprFactor();
has(')');
}
return ret;
}
public Mul parseTerm() throws Exception {
jumpspace();
Mul ret = new Mul();
if (issign(peak())) {
ret.multi(new Val(parseSign()));
}
jumpspace();
ret.multi(parseFactor());
jumpspace();
while (hasNext() && peak() == '*') {
pop();
ret.multi(parseFactor());
jumpspace();
}
return ret;
}
public Plus parseExprFactor() throws Exception {
jumpspace();
Plus ret = new Plus();
Mul tmp;
if (issign(peak())) {
tmp = new Mul(new Val(parseSign()), parseTerm());
}
else {
tmp = parseTerm();
}
ret.add(tmp);
jumpspace();
while (hasNext() && peak() != ')') {
if (parseSign() == 1) {
tmp = parseTerm();
}
else {
tmp = new Mul(new Val(-1), parseTerm());
}
ret.add(tmp);
jumpspace();
}
return ret;
}
public Plus parseExpr() throws Exception {
jumpspace();
Plus ret = new Plus();
Mul tmp;
if (issign(peak())) {
tmp = new Mul(new Val(parseSign()), parseTerm());
}
else {
tmp = parseTerm();
}
ret.add(tmp);
jumpspace();
while (hasNext()) {
if (parseSign() == 1) {
tmp = parseTerm();
}
else {
tmp = new Mul(new Val(-1), parseTerm());
}
ret.add(tmp);
jumpspace();
}
return ret;
}
}
加法节点逻辑如下
import java.math.BigInteger;
import java.util.ArrayList;
public class Plus implements Cal {
private ArrayList<Cal> arr;
public ArrayList<Cal> getarr() {
return arr;
}
@Override
public Cal Simplify() {
Val tmp = new Val(0);
ArrayList<Cal> narr = new ArrayList<Cal>(arr.size());
if (arr.size() == 1) {
return arr.get(0);
}
for (int i = 0;i < arr.size();i++) {
int rmflag = 0;
Cal ai = arr.get(i).Simplify();
if (ai instanceof Val) {
tmp.add((Val)ai);
rmflag = 1;
}
else if (ai instanceof Mul) {
Mul mai = (Mul) ai;
if (mai.getarr().size() == 1
&& (mai.getarr().get(0) instanceof Val)) {
tmp.add((Val) mai.getarr().get(0));
rmflag = 1;
}
}
else {
narr.add(ai);
rmflag = 1;
}
if (rmflag == 0) {
narr.add(ai);
}
}
if (!tmp.getVal().equals(BigInteger.ZERO)) {
narr.add(tmp);
}
else if (narr.isEmpty()) {
return tmp;
}
return new Plus(narr);
}
public Plus() {
arr = new ArrayList<Cal>(60);
}
public Plus(int size) {
arr = new ArrayList<Cal>(size);
}
public Plus(ArrayList<Cal> now) {
arr = now;
}
public Plus(Plus a,Plus b) {
ArrayList<Cal> aa = a.getarr();
ArrayList<Cal> bb = b.getarr();
arr = new ArrayList<Cal>(aa.size() + bb.size() + 10);
arr.addAll(aa);
arr.addAll(bb);
}
public Plus(Cal... arg) {
arr = new ArrayList<Cal>(arg.length * 2);
for (int i = 0; i < arg.length; i++) {
arr.add(arg[i]);
}
}
public void add(Cal now) {
arr.add(now);
}
public void add(Plus now) {
arr.addAll(now.getarr());
}
@Override
public Cal diff() {
Plus ret = new Plus(arr.size());
for (int i = 0;i < arr.size();i++) {
Cal zyy = arr.get(i).Simplify().diff().Simplify();
if (zyy instanceof Plus) {
ret.add((Plus) zyy);
} else {
ret.add(zyy);
}
}
ret.Simplify();
return ret;
}
@Override
public String toString() {
StringBuffer strbf = new StringBuffer();
for (int i = 0; i < arr.size(); i++) {
strbf.append(arr.get(i).toString());
if (i + 1 < arr.size()) {
strbf.append('+');
}
}
String ret = strbf.toString();
if (ret.length() == 0) {
return "0";
}
return ret;
}
}
乘法节点逻辑如下
import java.math.BigInteger;
import java.util.ArrayList;
public class Mul implements Cal {
private ArrayList<Cal> arr;
public ArrayList<Cal> getarr() {
return arr;
}
@Override
public Cal Simplify() {
ArrayList<Cal> narr = new ArrayList<Cal>(arr.size());
Val tmp = new Val(1);
Pow tmq = new Pow(BigInteger.ZERO);
if (arr.size() == 1) {
return arr.get(0);
}
for (int i = 0; i < arr.size(); i++) {
int svflag = 1;
Cal ai = arr.get(i).Simplify();
if (ai instanceof Val) {
tmp.multi((Val) ai);
svflag = 0;
}
else if (ai instanceof Pow) {
tmq.multi((Pow) ai);
svflag = 0;
}
if (svflag == 1) {
narr.add(ai);
}
}
if (tmp.getVal().equals(BigInteger.ZERO)) {
return tmp;
}
else if (!tmp.getVal().equals(BigInteger.ONE)) {
narr.add(tmp);
}
if (!tmq.getDeg().equals(BigInteger.ZERO)) {
narr.add(tmq);
}
if (narr.isEmpty()) {
return new Val(BigInteger.ONE);
}
return new Mul(narr);
}
public Mul() {
arr = new ArrayList<Cal>(60);
}
public Mul(int size) {
arr = new ArrayList<Cal>(size);
}
public Mul(Mul a,Mul b) {
ArrayList<Cal> aa = a.getarr();
ArrayList<Cal> bb = b.getarr();
arr = new ArrayList<Cal>(aa.size() + bb.size() + 10);
arr.addAll(aa);
arr.addAll(bb);
}
public Mul(Cal... arg) {
arr = new ArrayList<Cal>(arg.length * 2);
for (int i = 0; i < arg.length; i++) {
arr.add(arg[i]);
}
}
public Mul(ArrayList<Cal> now) {
arr = now;
}
public void multi(Cal now) {
arr.add(now);
}
public void multi(Mul now) {
arr.addAll(now.getarr());
}
@Override
public Cal diff() {
Plus ret = new Plus(arr.size());
ArrayList<Cal> tmp;
for (int i = 0; i < arr.size(); i++) {
tmp = (ArrayList<Cal>) arr.clone();
tmp.remove(i);
Cal xsy = arr.get(i).Simplify().diff().Simplify();
if (xsy instanceof Mul) {
tmp.addAll(((Mul) xsy).getarr());
} else {
tmp.add(xsy);
}
ret.add(new Mul(tmp));
}
return ret.Simplify();
}
@Override
public String toString() {
StringBuffer strbf = new StringBuffer();
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i) instanceof Plus) {
strbf.append('(');
}
strbf.append(arr.get(i).toString());
if (arr.get(i) instanceof Plus) {
strbf.append(')');
}
if (i + 1 < arr.size()) {
strbf.append('*');
}
}
return strbf.toString();
}
}
```
来源:CSDN
作者:Prime_min
链接:https://blog.csdn.net/Prime_min/article/details/104657347