Skip to main content
Code Review

Return to Question

removed off-topic request for resources
Source Link
200_success
  • 145.5k
  • 22
  • 190
  • 479

Math app/library that solves calculus problems(symbolic derivative, etc)

1) If I want to develop this into a more organized project, and perhaps a more general math library, with more functionality(integration, statisticssstatistics, etc), what can I do to design it very well? Where do I put the logic, etc. I have been reading up on design patterns but I still feel that I need direction.

2)What are some great resources for learning design/structure? I have "code complete", but I have only skimmed through it and it seems like it is for more experienced developers.

Lets say I want a gui as well.

etc, etc.

Math app/library that solves calculus problems(symbolic derivative, etc)

1) If I want to develop this into a more organized project, and perhaps a more general math library, with more functionality(integration, statisticss, etc), what can I do to design it very well? Where do I put the logic, etc. I have been reading up on design patterns but I still feel that I need direction.

2)What are some great resources for learning design/structure? I have "code complete", but I have only skimmed through it and it seems like it is for more experienced developers.

Lets say I want a gui as well.

etc, etc.

Math app/library that solves calculus problems(symbolic derivative, etc)

If I want to develop this into a more organized project, and perhaps a more general math library, with more functionality(integration, statistics, etc), what can I do to design it very well? Where do I put the logic, etc. I have been reading up on design patterns but I still feel that I need direction.

Source Link

Math app/library that solves calculus problems(symbolic derivative, etc)

Let me start off by saying that this project is a mess, and I know it. I believe it is a mess because I threw it together in a few days just to get it working. Unfortunately, my undergraduate education hasn't taught me design patterns(yet), so there is really no organized structure.

1) If I want to develop this into a more organized project, and perhaps a more general math library, with more functionality(integration, statisticss, etc), what can I do to design it very well? Where do I put the logic, etc. I have been reading up on design patterns but I still feel that I need direction.

2) What are some great resources for learning design/structure? I have "code complete", but I have only skimmed through it and it seems like it is for more experienced developers.

Lets say I want a gui as well.

etc, etc.

MathApp.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javax.swing.*;
public class MathApp extends Application {
 private CalculusTool cT;
 private String expression;
 private String deriv;
 @Override
 public void start(Stage primaryStage) {
 primaryStage.setTitle("MathApp");
 GridPane grid = new GridPane();
 grid.setAlignment(Pos.CENTER);
 grid.setHgap(10);
 grid.setVgap(10);
 grid.setPadding(new Insets(25, 25, 25, 25));
 Text scenetitle = new Text("Enter an expression");
 scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 15));
 grid.add(scenetitle, 0, 0, 2, 1);
 TextField expBox = new TextField();
 grid.add(expBox, 1, 2);
 Text error = new Text();
 grid.add(error, 1, 6);
 error.setVisible(false);
 Button btn = new Button("Derive");
 HBox hbBtn = new HBox(10);
 hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
 hbBtn.getChildren().add(btn);
 grid.add(hbBtn, 1, 4);
 final Text actiontarget = new Text();
 grid.add(actiontarget, 1, 6);
 btn.setOnAction(new EventHandler<ActionEvent>() {
 @Override
 public void handle(ActionEvent e) {
 //same expression - derive again when clicked
 if(expBox.hasProperties() && expBox.getText().equals(expression)) {
 deriv = cT.readable(cT.derive());
 actiontarget.setVisible(true);
 actiontarget.setFill(Color.FIREBRICK);
 actiontarget.setText(deriv);
 }
 else { // new expression, create new object
 expression = expBox.getText();
 if (!CalculusTool.isValidExpression(expression)) {
 actiontarget.setVisible(false);
 error.setText(CalculusTool.errorMessage);
 error.setVisible(true);
 expBox.clear();
 } else {
 error.setVisible(false);
 cT = new CalculusTool(expression);
 deriv = cT.readable(cT.derive());
 actiontarget.setVisible(true);
 actiontarget.setFill(Color.FIREBRICK);
 actiontarget.setText(deriv);
 }
 }
 }
 });
 Scene scene = new Scene(grid, 300, 275);
 primaryStage.setScene(scene);
 primaryStage.show();
 }
 public static void main(String[] args) {
 launch(args);
 }
}

ExpNode.java

abstract class ExpNode {
 abstract String getVal();
 abstract String getType();
 abstract ExpNode getLeftChild();
 abstract ExpNode getRightChild();
 abstract void setLeftChild(ExpNode l);
 abstract void setRightChild(ExpNode r);
 abstract ExpNode derivative();
}
class OpNode extends ExpNode
{
 String operator;
 ExpNode leftChild;
 ExpNode rightChild;
 OpNode mult1;
 OpNode mult2;
 OpNode mult3;
 OpNode div;
 OpNode plus;
 OpNode minus;
 OpNode exponent;
 NegateNode unary;
 OpNode(String op)
 {
 operator = op;
 leftChild = null;
 rightChild = null;
 }
 String getVal() { return operator; }
 String getType() { return "operator"; }
 ExpNode getLeftChild() { return leftChild; }
 ExpNode getRightChild() { return rightChild; }
 void setLeftChild(ExpNode lc) { leftChild = lc; }
 void setRightChild(ExpNode rc) { rightChild = rc; }
 ExpNode derivative() {
 switch(operator) {
 case "+": // h(x) = f(x)+g(x) then h′(x) = f′(x)+g′(x)
 plus = new OpNode("+");
 plus.setLeftChild(getLeftChild().derivative());
 plus.setRightChild(getRightChild().derivative());
 return plus;
 case "-": // h(x) = f(x)-g(x) then h′(x) = f′(x)-g′(x)
 minus = new OpNode("-");
 minus.setLeftChild(getLeftChild().derivative());
 minus.setRightChild(getRightChild().derivative());
 return minus;
 case "*": // h(x) = f(x)g(x) then h′(x) = f′(x)g(x) + f(x)g′(x)
 mult1 = new OpNode("*");
 mult2 = new OpNode("*");
 plus = new OpNode("+");
 mult1.setLeftChild(getLeftChild());
 mult1.setRightChild(getRightChild().derivative());
 mult2.setLeftChild(getRightChild());
 mult2.setRightChild(getLeftChild().derivative());
 plus.setLeftChild(mult1);
 plus.setRightChild(mult2);
 return plus;
 case "/": // h(x) = f(x)/g(x) then h′(x) = (f′(x)g(x) − f(x)g′(x))/( g(x)^2)
 mult1 = new OpNode("*");
 mult2 = new OpNode("*");
 mult3 = new OpNode("*");
 div = new OpNode("/");
 minus = new OpNode("-");
 mult1.setLeftChild(getRightChild());
 mult1.setRightChild(getLeftChild().derivative());
 mult2.setLeftChild(getLeftChild());
 mult2.setRightChild(getRightChild().derivative());
 minus.setLeftChild(mult1);
 minus.setRightChild(mult2);
 mult3.setLeftChild(getRightChild());
 mult3.setRightChild(getRightChild());
 div.setLeftChild(minus);
 div.setRightChild(mult3);
 return div;
 case "^":
 /*y = xsin x
 ln y = (sin x) ln x ← taking the natural log of both sides.
 y'/y = (cos x) ln x + (sin x)/x ← Using the product rule and implicit differentiation.
 y' = y((cos x) ln x + (sin x)/x) ← multiplying by y.
 y' = xsin x ((cos x) ln x + (sin x)/x) ← substitution.
 */
 if(getRightChild().getVal().equals("0")) {
 return new ConstNode("1");
 }
 if(getLeftChild().getType().equals("function")) {
 if(getRightChild().getType().equals("variable")) {
 }
 if(getRightChild().getType().equals("function")) {
 }
 if(getRightChild().getType().equals("constant")) {
 int temp = Integer.parseInt(getRightChild().getVal());
 temp--;
 ConstNode decrement = new ConstNode(String.valueOf(temp));
 mult1 = new OpNode("*");
 mult2 = new OpNode("*");
 exponent = new OpNode("^");
 //getLeftChild() = func(x)
 //getLeftChild().derivative() = dx*dfunc(x)
 //getRightChild() = C
 //decrement = C - 1
 //getLeftChild().getRightChild() = x
 // func(x)^C ==>> C*dx*func(x)^(C-1)*dfunc(x)
 exponent.setLeftChild(getLeftChild());
 exponent.setRightChild(decrement);
 mult1.setLeftChild(exponent);
 mult1.setRightChild(getLeftChild().derivative());
 mult2.setLeftChild(getRightChild());
 mult2.setRightChild(mult1);
 return mult2;
 }
 }
 else if(getLeftChild().getType().equals("variable")) {
 if(getRightChild().getType().equals("unaryMinus")) {
 if(getRightChild().getRightChild().getType().equals("constant")) { // Ex: x^-3 ==> -3*(x^-4)
 int temp = Integer.parseInt(getRightChild().getRightChild().getVal());
 temp++;
 ConstNode decrement = new ConstNode(String.valueOf(temp));
 mult1 = new OpNode("*");
 exponent = new OpNode("^");
 unary.setRightChild(getRightChild().getRightChild());
 exponent.setLeftChild(getLeftChild());
 exponent.setRightChild(decrement);
 mult1.setLeftChild(unary);
 mult1.setRightChild(exponent);
 return mult1;
 }
 }
 // if not unaryMinus
 if(getRightChild().getType().equals("variable")) {
 }
 if(getRightChild().getType().equals("function")) {
 }
 if(getRightChild().getType().equals("constant")) { // Ex: x^3 ==> 3*(x^2)
 int temp = Integer.parseInt(getRightChild().getVal());
 temp--;
 ConstNode decrement = new ConstNode(String.valueOf(temp));
 mult1 = new OpNode("*");
 exponent = new OpNode("^");
 exponent.setLeftChild(getLeftChild());
 exponent.setRightChild(decrement);
 mult1.setLeftChild(getRightChild());
 mult1.setRightChild(exponent);
 return mult1;
 }
 }
 else if(getLeftChild().getType().equals("constant")) {
 if(getRightChild().getType().equals("variable")) {
 }
 if(getRightChild().getType().equals("function")) {
 }
 if(getRightChild().getType().equals("constant")) {
 return new ConstNode("0");
 }
 }
 return new ConstNode("0");
 }
 return null;
 }
}
// only has right child
class FuncNode extends ExpNode
{
 String func;
 ExpNode leftChild;
 ExpNode rightChild;
 NegateNode unary;
 OpNode exponent;
 OpNode mult;
 OpNode mult2;
 OpNode div;
 FuncNode sin;
 FuncNode cos;
 FuncNode sec;
 FuncNode cot;
 FuncNode csc;
 FuncNode tan;
 FuncNode ln;
 ConstNode two;
 ConstNode ten;
 FuncNode(String f)
 {
 func = f;
 leftChild = null;
 rightChild = null;
 }
 String getVal() { return func; }
 String getType() { return "function"; }
 ExpNode getLeftChild() { return leftChild; }
 ExpNode getRightChild() { return rightChild; }
 void setLeftChild(ExpNode lc) { leftChild = lc; }
 void setRightChild(ExpNode rc) { rightChild = rc; }
 ExpNode derivative() {
 switch(func) {
 case "sin":
 mult = new OpNode("*");
 cos = new FuncNode("cos");
 cos.setRightChild(getRightChild());
 mult.setLeftChild(getRightChild().derivative());
 mult.setRightChild(cos);
 return mult;
 case "cos":
 unary = new NegateNode();
 mult = new OpNode("*");
 sin = new FuncNode("sin");
 sin.setRightChild(getRightChild());
 mult.setLeftChild(getRightChild().derivative());
 mult.setRightChild(sin);
 unary.setRightChild(mult);
 return unary;
 case "tan":
 sec = new FuncNode("sec");
 mult = new OpNode("*");
 exponent = new OpNode("^");
 two = new ConstNode("2");
 sec.setRightChild(getRightChild());
 exponent.setLeftChild(sec);
 exponent.setRightChild(two);
 mult.setLeftChild(getRightChild().derivative());
 mult.setRightChild(exponent);
 return mult;
 case "csc":
 unary = new NegateNode();
 mult = new OpNode("*");
 mult2 = new OpNode("*");
 cot = new FuncNode("cot");
 csc = new FuncNode("csc");
 cot.setRightChild(getRightChild());
 csc.setRightChild(getRightChild());
 mult.setLeftChild(cot);
 mult.setRightChild(csc);
 mult2.setLeftChild(getRightChild().derivative());
 mult2.setRightChild(mult);
 unary.setRightChild(mult2);
 return unary;
 case "sec":
 mult = new OpNode("*");
 mult2 = new OpNode("*");
 sec = new FuncNode("sec");
 tan = new FuncNode("tan");
 sec.setRightChild(getRightChild());
 tan.setRightChild(getRightChild());
 mult.setLeftChild(sec);
 mult.setRightChild(tan);
 mult2.setLeftChild(getRightChild().derivative());
 mult2.setRightChild(mult);
 return mult2;
 case "cot":
 unary = new NegateNode();
 exponent = new OpNode("^");
 mult = new OpNode("*");
 csc = new FuncNode("csc");
 two = new ConstNode("2");
 csc.setRightChild(getRightChild());
 exponent.setLeftChild(csc);
 exponent.setRightChild(two);
 mult.setLeftChild(getRightChild().derivative());
 mult.setRightChild(exponent);
 unary.setRightChild(mult);
 return unary;
 case "log":
 div = new OpNode("/");
 mult = new OpNode("*");
 ln = new FuncNode("ln");
 ten = new ConstNode("10");
 ln.setRightChild(ten);
 mult.setLeftChild(getRightChild());
 mult.setRightChild(ln);
 div.setLeftChild(getRightChild().derivative());
 div.setRightChild(mult);
 return div;
 case "ln":
 div = new OpNode("/");
 div.setLeftChild(getRightChild().derivative());
 div.setRightChild(getRightChild());
 return div;
 //case "arcsin":
 //case "arccos":
 }
 return null;
 }
}
class ConstNode extends ExpNode
{
 int num;
 String strNum;
 ExpNode leftChild;
 ExpNode rightChild;
 boolean string = false;
 ConstNode(int val)
 {
 num = val;
 strNum = "";
 leftChild = null;
 rightChild = null;
 }
 ConstNode(String val)
 {
 strNum = val;
 num = 0;
 leftChild = null;
 rightChild = null;
 string = true;
 }
 String getVal() { return strNum; }
 String getType() { return "constant"; }
 ExpNode getLeftChild() { return leftChild; }
 ExpNode getRightChild() { return rightChild; }
 void setLeftChild(ExpNode lc) { leftChild = lc; }
 void setRightChild(ExpNode rc) { rightChild = rc; }
 ExpNode derivative() { return new ConstNode("0"); }
}
class VarNode extends ExpNode
{
 String variable;
 ExpNode leftChild;
 ExpNode rightChild;
 VarNode(String v)
 {
 variable = v;
 leftChild = null;
 rightChild = null;
 }
 String getVal() { return variable; }
 String getType() { return "variable"; }
 ExpNode getLeftChild() { return leftChild; }
 ExpNode getRightChild() { return rightChild; }
 void setLeftChild(ExpNode lc) { leftChild = lc; }
 void setRightChild(ExpNode rc) { rightChild = rc; }
 ExpNode derivative() {
 return new ConstNode("1");
 }
}
// $ only has a right child
class NegateNode extends ExpNode
{
 String unaryMinus;
 ExpNode leftChild;
 ExpNode rightChild;
 NegateNode unary;
 NegateNode()
 {
 unaryMinus = "$";
 leftChild = null;
 rightChild = null;
 }
 NegateNode(String un)
 {
 unaryMinus = un;
 leftChild = null;
 rightChild = null;
 }
 String getVal() { return unaryMinus; }
 String getType() { return "unaryMinus"; }
 ExpNode getLeftChild() { return leftChild; }
 ExpNode getRightChild() { return rightChild; }
 void setLeftChild(ExpNode lc) { leftChild = lc; }
 void setRightChild(ExpNode rc) { rightChild = rc; }
 ExpNode derivative() {
 if(getRightChild().getType().equals("constant")) {
 return new ConstNode("0");
 }
 unary = new NegateNode("$");
 unary.setRightChild(getRightChild().derivative());
 return unary;
 }
}

CalculusTool.java

import java.util.ArrayList;
import java.util.Stack;
public class CalculusTool {
 public static String var = "";
 private String expression;
 private String derivative;
 private ArrayList<String> postFixTokens;
 private ExpNode root;
 private ExpNode derivativeRoot;
 private int COUNT = 10;
 static String errorMessage;
 public CalculusTool(String exp)
 {
 expression = formatString(exp);
 postFixTokens = tokenize(expression);
 root = constructTree(postFixTokens);
 derivativeRoot = root;
 derivative = expression;
 }
 public String getExpression()
 {
 return expression;
 }
 public void resetDerivative()
 {
 derivativeRoot = root;
 derivative = expression;
 }
 public static boolean isValidExpression(String exp)
 {
 exp = exp.replaceAll("\\s","");
 exp = exp.toLowerCase();
 if(exp.length() == 0) {
 errorMessage = "Nothing Entered";
 return false;
 }
 if(!exp.matches("[a-zA-Z0-9+*/^()-]+")) { // contains only operators, numbers, or letters
 errorMessage = "Syntax Error";
 return false;
 }
 if(exp.matches("[+*/^()-]+")) { // doesn't contain any operands
 errorMessage = "Syntax Error";
 return false;
 }
 String firstChar = exp.substring(0, 1);
 String lastChar = exp.substring(exp.length() - 1, exp.length());
 if(!firstChar.equals("-") && isOperator(firstChar) || firstChar.equals(")") || isOperator(lastChar) || lastChar.equals("(")) {
 errorMessage = "Syntax Error"; //starts with operator or close parenthesis, or ends with operator or open parenthesis
 return false;
 }
 for(int i = 0; i < exp.length(); i++) {
 String temp = "";
 while(i < exp.length() && exp.substring(i, i + 1).matches("[a-zA-Z]")) {
 temp += exp.substring(i, i + 1);
 i++;
 }
 if(temp.length() == 1) {
 //i--; // ?? i must be decremented from the above while loop in this if block so the program can check the last character in the string
 if(var.length() == 0)
 var = temp;
 if(!temp.equals(var)) {
 errorMessage = "Your expression cannot contain two variables";
 return false;
 }
 else if(i < exp.length() && exp.substring(i, i + 1).matches("[0-9]+")) {
 errorMessage = "Can't do this: " + temp + exp.substring(i, i + 1);
 return false;
 }
 }
 else if(isFunction(temp)) {
 if(i < exp.length()) {
 if(!exp.substring(i, i + 1).equals("(")) {
 System.out.println("Syntax Error: " + temp + " needs a parenthesis after it");// no parenthesis after function (EX: sin5)
 return false;
 }
 }
 else {
 System.out.println("Syntax Error: " + temp + " needs an input"); // nothing after function (EX: 5 + sin)
 return false;
 }
 }
 else if(temp.length() != 0){
 System.out.println(temp + ": function not found");
 return false;
 }
 //i--; // ?? i must be decremented since it was left incremented in the above while loop
 }
 int cntOpenParen = 0;
 int cntCloseParen = 0;
 for(int i = 0; i < exp.length() - 1; i++) {
 String tmp1 = exp.substring(i, i + 1);
 String tmp2 = exp.substring(i + 1, i + 2);
 if(tmp1.equals("-")) {
 if(isOperator(tmp2) || tmp2.equals(")")) {
 System.out.println("Syntax Error: " + tmp1 + tmp2);
 return false;
 }
 }
 else if(tmp2.equals("-")) { // Also prevents next else if from rejecting an operator followed by a unary minus
 if(tmp1.equals("(")) {
 System.out.println("Syntax Error: " + tmp1 + tmp2);
 return false;
 }
 }
 else if((isOperator(tmp1) || tmp1.equals("(")) && (isOperator(tmp2) || tmp2.equals(")"))) {
 System.out.println("Syntax Error: " + tmp1 + tmp2); // two operands in a row (examples: ++, (+, ())
 return false;
 }
 else if(exp.substring(i, i + 1).equals("("))
 cntOpenParen++;
 else if(exp.substring(i, i + 1).equals(")"))
 cntCloseParen++;
 }
 if(cntOpenParen < cntCloseParen) { // found a ")" when the end of the expression was expected
 System.out.println("Syntax Error: found ')' but expected end of expression");
 return false;
 }
 return true;
 }
 public static boolean isOperator(String str)
 {
 if(str.matches("[+*/^-]"))
 return true;
 return false;
 }
 public boolean isOperand(String str)
 {
 if(str.matches("[0-9]+") || str.equals(var))
 return true;
 return false;
 }
 public static boolean isFunction(String str)
 {
 String[] funcs = {"sin", "cos", "tan", "csc", "sec", "cot", "log", "ln"};
 for(String temp: funcs)
 if(str.equals(temp))
 return true;
 return false;
 }
 // "simplifies" the tree by deleting, replacing and merging nodes
 public ExpNode simplify(ExpNode root)
 {
 if(root == null)
 {
 return root;
 }
 else if(root.getType().equals("unaryMinus") && root.getRightChild().getType().equals("unaryMinus")) {
 return root.getRightChild().getRightChild();
 }
 else if(root.getVal().equals("*")) {
 if(root.getLeftChild().getVal().equals("1")) {
 return root.getRightChild();
 }
 else if(root.getRightChild().getVal().equals("1")) {
 return root.getLeftChild();
 }
 else if(root.getLeftChild().getVal().equals("0")) {
 return root.getLeftChild();
 }
 else if(root.getRightChild().getVal().equals("0")) {
 return root.getRightChild();
 }
 else if(root.getLeftChild().getVal().equals("*")) {
 if(root.getRightChild().getType().equals("constant")) {
 if(root.getLeftChild().getLeftChild().getType().equals("constant")) { // Ex: (5*x)*6 ==> 30*x
 int num1 = Integer.parseInt(root.getRightChild().getVal());
 int num2 = Integer.parseInt(root.getLeftChild().getLeftChild().getVal());
 OpNode mult = new OpNode("*");
 mult.setLeftChild(new ConstNode(String.valueOf(num1 * num2)));
 mult.setRightChild(root.getLeftChild().getRightChild());
 return mult;
 }
 if(root.getLeftChild().getRightChild().getType().equals("constant")) { // Ex: (x*5)*6 ==> 30*x
 int num1 = Integer.parseInt(root.getRightChild().getVal());
 int num2 = Integer.parseInt(root.getLeftChild().getRightChild().getVal());
 OpNode mult = new OpNode("*");
 mult.setLeftChild(new ConstNode(String.valueOf(num1 * num2)));
 mult.setRightChild(root.getLeftChild().getLeftChild());
 return mult;
 }
 }
 if(root.getRightChild().getType().equals("variable")) {
 if(root.getLeftChild().getLeftChild().getType().equals("variable")) {
 OpNode exponent = new OpNode("^");
 exponent.setLeftChild(root.getRightChild());
 exponent.setRightChild(new ConstNode("2"));
 if(root.getLeftChild().getRightChild().getType().equals("function")) { // Ex: (x*sin(x))*x ==> (x^2)*sin(x)
 root.setRightChild(root.getLeftChild().getRightChild());
 root.setLeftChild(exponent);
 }
 else { // Ex: (x*5)*x ==> 5*x^2
 root.setRightChild(exponent);
 root.setLeftChild(root.getLeftChild().getRightChild());
 }
 return root;
 }
 if(root.getLeftChild().getRightChild().getType().equals("variable")) {
 OpNode exponent = new OpNode("^");
 exponent.setLeftChild(root.getRightChild());
 exponent.setRightChild(new ConstNode("2"));
 if(root.getLeftChild().getLeftChild().getType().equals("function")) { // Ex: (sin(x)*x)*x ==> (x^2)*sin(x)
 root.setRightChild(root.getLeftChild().getLeftChild());
 root.setLeftChild(exponent);
 }
 else { // Ex: (5*x)*x ==> 5*x^2
 root.setRightChild(exponent);
 root.setLeftChild(root.getLeftChild().getLeftChild());
 }
 return root;
 }
 }
 }
 else if(root.getRightChild().getVal().equals("*")) {
 if(root.getLeftChild().getType().equals("constant")) {
 if(root.getRightChild().getLeftChild().getType().equals("constant")) { // Ex: 5*(6*x) ==> 30*x
 int num1 = Integer.parseInt(root.getLeftChild().getVal());
 int num2 = Integer.parseInt(root.getRightChild().getLeftChild().getVal());
 OpNode mult = new OpNode("*");
 mult.setLeftChild(new ConstNode(String.valueOf(num1 * num2)));
 mult.setRightChild(root.getRightChild().getRightChild());
 return mult;
 }
 if(root.getRightChild().getRightChild().getType().equals("constant")) { // Ex: 5*(x*6) ==> 30*x
 int num1 = Integer.parseInt(root.getLeftChild().getVal());
 int num2 = Integer.parseInt(root.getRightChild().getRightChild().getVal());
 OpNode mult = new OpNode("*");
 mult.setLeftChild(new ConstNode(String.valueOf(num1 * num2)));
 mult.setRightChild(root.getRightChild().getLeftChild());
 return mult;
 }
 }
 if(root.getLeftChild().getType().equals("variable")) {
 if(root.getRightChild().getLeftChild().getType().equals("variable")) {
 OpNode exponent = new OpNode("^");
 exponent.setLeftChild(root.getLeftChild());
 exponent.setRightChild(new ConstNode("2"));
 if(root.getRightChild().getRightChild().getType().equals("function")) { // Ex: x*(x*sin(x)) ==> (x^2)*sin(x)
 root.setRightChild(root.getRightChild().getRightChild());
 root.setLeftChild(exponent);
 }
 else { // Ex: x*(x*5) ==> 5*x^2
 root.setRightChild(exponent);
 root.setLeftChild(root.getRightChild().getRightChild());
 }
 return root;
 }
 if(root.getRightChild().getRightChild().getType().equals("variable")) {
 OpNode exponent = new OpNode("^");
 exponent.setLeftChild(root.getLeftChild());
 exponent.setRightChild(new ConstNode("2"));
 if(root.getRightChild().getLeftChild().getType().equals("function")) { // Ex: x*(sin(x)*x) ==> (x^2)*sin(x)
 root.setRightChild(root.getRightChild().getLeftChild());
 root.setLeftChild(exponent);
 }
 else {
 root.setRightChild(exponent);
 root.setLeftChild(root.getRightChild().getLeftChild()); // Ex: x*(5*x) ==> 5*x^2
 }
 return root;
 }
 }
 }
 else if(root.getLeftChild().getVal().equals("^") && root.getRightChild().getVal().equals("^")) {
 }
 else if(root.getLeftChild().getVal().equals("^")) { // Ex: (x^2)*x
 }
 else if(root.getRightChild().getVal().equals("^")) { // Ex: x*(x^2)
 if(root.getLeftChild().getType().equals("variable") && root.getRightChild().getLeftChild().getType().equals("variable")) {
 }
 }
 else if(root.getLeftChild().getType().equals("unaryMinus")) {
 if(root.getRightChild().getType().equals("constant") && root.getLeftChild().getRightChild().getType().equals("constant")) {
 int num1 = Integer.parseInt(root.getRightChild().getVal());
 int num2 = Integer.parseInt(root.getLeftChild().getRightChild().getVal());
 NegateNode unary = new NegateNode("$");
 unary.setRightChild(new ConstNode(String.valueOf(num1 * num2)));
 return unary;
 }
 }
 else if(root.getRightChild().getType().equals("unaryMinus")) {
 if(root.getLeftChild().getType().equals("constant") && root.getRightChild().getRightChild().getType().equals("constant")) {
 int num1 = Integer.parseInt(root.getLeftChild().getVal());
 int num2 = Integer.parseInt(root.getRightChild().getRightChild().getVal());
 NegateNode unary = new NegateNode("$");
 unary.setRightChild(new ConstNode(String.valueOf(num1 * num2)));
 return unary;
 }
 }
 // Ex: x*x ==> x^2
 else if(root.getLeftChild().getType().equals("variable") && root.getRightChild().getType().equals("variable")) {
 OpNode exponent = new OpNode("^");
 exponent.setLeftChild(root.getLeftChild());
 exponent.setRightChild(new ConstNode("2"));
 return exponent;
 }
 else if(root.getLeftChild().getType().equals("constant") && root.getRightChild().getType().equals("constant")) {
 int num1 = Integer.parseInt(root.getLeftChild().getVal());
 int num2 = Integer.parseInt(root.getRightChild().getVal());
 return new ConstNode(String.valueOf(num1 * num2));
 }
 }
 else if(root.getVal().equals("+")) {
 if(root.getLeftChild().getVal().equals("0")) {
 return root.getRightChild();
 }
 else if(root.getRightChild().getVal().equals("0")) {
 return root.getLeftChild();
 }
 }
 else if(root.getVal().equals("^")) {
 if(root.getRightChild().getVal().equals("1")) {
 return root.getLeftChild();
 }
 }
 root.setLeftChild(simplify(root.getLeftChild()));
 root.setRightChild(simplify(root.getRightChild()));
 return root;
 }
 public String derive()
 {
 derivativeRoot = derivativeRoot.derivative();
 // need to change simplfy to do depth-first traversal so that the
 // tree will be fully "simplified" after one call
 derivativeRoot = simplify(derivativeRoot);
 derivativeRoot = simplify(derivativeRoot);
 derivativeRoot = simplify(derivativeRoot);
 return createInfix(derivativeRoot);
 }
 public int getPrecedence(String str)
 {
 int val = 0;
 if(str.equals("+"))
 val = 2;
 else if(str.equals("-"))
 val = 2;
 else if(str.equals("*") || str.equals(("/")))
 val = 3;
 else if(str.equals("^") || str.equals("$"))
 val = 4;
 return val;
 }
 public boolean isLeftAssociative(String s)
 {
 if(s.equals("^") || s.equals("$") || s.equals("+") || s.equals("*"))
 return false;
 return true;
 }
 // modifies the string to look more like it would if someone wrote the expression
 // out on paper
 public String readable(String s)
 {
 for(int i = 0; i < s.length(); i++) {
 if(s.substring(i, i + 1).equals("*") && i > 0)
 if(isOperand(s.substring(i - 1, i)) && i < s.length() - 1 && s.substring(i + 1, i + 2).equals(var))
 s = s.substring(0, i) + s.substring(i + 1);
 }
 return s;
 }
 // adds and deletes characters to aid in the creation of the binary expression tree
 public String formatString(String exp)
 {
 exp = exp.replaceAll("\\s",""); // why
 exp = exp.toLowerCase();
 int count = 0;
 if(exp.substring(0, 1).equals("-")) { // if expression starts with a minus sign, it is a unary one
 exp = "$" + exp.substring(1); // replace
 }
 for(int i = 0; i < exp.length(); i++) {
 if(exp.substring(i, i + 1).equals("("))
 count++;
 else if(exp.substring(i, i + 1).equals(")"))
 count--;
 }
 while(count > 0) {
 exp += ")";
 count--;
 }
 // At the operators, when the operator is "-" and it is preceded by another operator,
 // or preceded by a left parenthesis, or when it is the first character of the input
 // it is a unary minus rather than binary. In this case, I change it to another
 // character, '$', and make its precedence the same as that of '^'.
 for(int i = 0; i < exp.length() - 1; i++) {
 String tmp1 = exp.substring(i, i + 1);
 String tmp2 = exp.substring(i + 1, i + 2);
 if(tmp2.equals("-") && (isOperator(tmp1) || tmp1.equals("(")))
 exp = exp.substring(0, i + 1) + "$" + exp.substring(i + 2);
 else if((tmp1.matches("[0-9]+") || tmp1.equals(var)) && (tmp2.equals("(") || tmp2.equals(var)))
 exp = exp.substring(0, i + 1) + "*" + exp.substring(i + 1);
 }
 return exp;
 }
 //creates string representing infix expression
 public String createInfix(ExpNode root)
 {
 String str = "";
 if(root == null) {
 return str;
 }
 if (root != null) {
 if (root.getRightChild() == null) {
 str += root.getVal();
 }
 else if(root.getType().equals("function")) {
 str += root.getVal();
 //str += "(";
 }
 else if(root.getType().equals("unaryMinus")) {
 str += "-";
 }
 else {
 int parentPrecedence = getPrecedence(root.getVal());
 str += root.getVal();
 if(root.getLeftChild() != null && (getPrecedence(root.getLeftChild().getVal()) < parentPrecedence || isLeftAssociative(root.getLeftChild().getVal()))) {
 //str += "(";
 }
 /*if(getPrecedence(root.getRightChild().getVal()) < parentPrecedence) {
 str += ")";
 }*/
 }
 }
 return createInfix(root.getLeftChild()) + str + createInfix(root.getRightChild());
 }
 // separates the expression string into "tokens" and sorts them in
 // postfix order
 public ArrayList<String> tokenize(String exp)
 {
 ArrayList<String> tokens = new ArrayList<>();
 Stack<String> stack = new Stack<>();
 for(int i = 0; i < exp.length(); i++)
 {
 String token = "";
 if(isOperator(exp.substring(i, i + 1)) || exp.substring(i, i + 1).equals("$")) {
 token = exp.substring(i, i + 1);
 while ((!stack.isEmpty() && (isOperator(stack.peek()) || stack.peek().equals("$")))
 && ((isLeftAssociative(token) && getPrecedence(token) <= getPrecedence(stack.peek()))
 || (!isLeftAssociative(token) && getPrecedence(token) < getPrecedence(stack.peek())))) {
 tokens.add(stack.pop());
 }
 stack.push(token);
 }
 else if(exp.substring(i, i + 1).equals(var)) {
 token = var;
 tokens.add(token);
 }
 else if(exp.substring(i, i + 1).equals("(")) {
 token = exp.substring(i, i + 1);
 stack.push(token);
 }
 else if(exp.substring(i, i + 1).equals(")")) {
 while(!stack.isEmpty() && !stack.peek().equals("(")) {
 tokens.add(stack.pop());
 }
 if(!stack.isEmpty())
 stack.pop();
 if(!stack.isEmpty() && isFunction(stack.peek())) {
 tokens.add(stack.pop());
 }
 }
 else if(exp.substring(i, i + 1).matches("[0-9]+")) {
 while(i < exp.length() && exp.substring(i, i + 1).matches("[0-9]+")) {
 token += exp.substring(i, i + 1);
 i++;
 }
 tokens.add(token);
 i--; // i was left incremented after the while loop
 }
 else if(exp.substring(i, i + 1).equals(var)) {
 tokens.add(token);
 }
 else {
 while(i < exp.length() && exp.substring(i, i + 1).matches("[a-zA-Z]+")) {
 token += exp.substring(i, i + 1);
 i++;
 }
 if(token.length() != 0) {
 stack.push(token);
 }
 }
 }
 while(!stack.isEmpty()) {
 tokens.add(stack.pop());
 }
 return tokens;
 }
 // reads the "tokens" in order from the list and builds a tree
 public ExpNode constructTree(ArrayList<String> postTokens)
 {
 ExpNode root = null;
 Stack<ExpNode> nodes = new Stack<>();
 for(String str: postTokens)
 {
 if(str.matches("[0-9]+")) {
 nodes.push(new ConstNode(str));
 }
 else if(str.equals(var))
 nodes.push(new VarNode(var));
 else if(!nodes.isEmpty() && isFunction(str)) {
 FuncNode function = new FuncNode(str);
 function.setRightChild(nodes.pop());
 nodes.push(function);
 }
 else if(!nodes.isEmpty() && str.equals("$")) {
 NegateNode unary = new NegateNode("$");
 unary.setRightChild(nodes.pop());
 nodes.push(unary);
 }
 else if(!nodes.isEmpty()){
 OpNode operator = new OpNode(str);
 operator.setRightChild(nodes.pop());
 operator.setLeftChild(nodes.pop());
 nodes.push(operator);
 }
 }
 if(!nodes.isEmpty())
 root = nodes.pop();
 return root;
 }
}
lang-java

AltStyle によって変換されたページ (->オリジナル) /