Skip to content

Instantly share code, notes, and snippets.

@boxbeam
Last active April 15, 2018 23:09
Show Gist options
  • Save boxbeam/8f2e005909f2fa48d46eb45dc84e8ed8 to your computer and use it in GitHub Desktop.
Save boxbeam/8f2e005909f2fa48d46eb45dc84e8ed8 to your computer and use it in GitHub Desktop.
package redempt.polishnotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
public class Expression {
private String expression;
public Expression(String expression) {
this.expression = parse(expression);
}
private static String parse(String input) {
for (Constant constant : Constant.values()) {
input = input.replace(constant.getName(), constant.getValue() + "");
}
input = input.replace(" ", "");
input = input.replace("-x", "-1*x");
input = input.replaceAll("([0-9.a-zA-Z)])-([0-9.a-zA-Z(])", "$1m$2");
input = input.replaceAll("([0-9x)])x", "$1*x");
input = input.replaceAll("\\)\\(", ")*(");
input = input.replaceAll("\\(([0-9x-]+)\\)", "$1");
for (Operation operation : Operation.values()) {
if (operation.getAltName() != null) {
input = input.replace(operation.getAltName(), operation.getName() + "");
}
}
char[] chars = input.toCharArray();
String output = "";
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c == '(' || c == ')') {
output += c + " ";
continue;
}
for (Operation operation : Operation.values()) {
if (operation.getName() != c) {
continue;
}
output += c + " ";
}
}
output = output.trim();
output += "`";
String[] split = input.split("[^0-9-x.]");
for (String num : split) {
if (num.equals("")) {
continue;
}
output += num + " ";
}
return output.trim();
}
public double evaluate(double value) {
String[] split = expression.split("`");
List<Operation> operations = Arrays.stream(split[0].split(" ")).map(Operation::byName).collect(Collectors.toList());
List<Double> numbers = Arrays.stream(split[1].split(" ")).map(c -> c.replace("x", value + "")).map(Double::parseDouble).collect(Collectors.toList());
return evaluate(operations, numbers);
}
public double evaluate() {
return evaluate(0);
}
private static double evaluate(List<Operation> operations, List<Double> numbers) {
stuff:
while (numbers.size() >= 1 && operations.size() > 0) {
int lowest = -1;
for (int i = 0; i < operations.size(); i++) {
Operation operation = operations.get(i);
if (lowest == -1 || operation.getOrder() < operations.get(lowest).getOrder()) {
lowest = i;
}
}
Operation operation = operations.get(lowest);
if (operation == null) {
return numbers.get(0);
}
if (operation == Operation.OPAREN) {
int depth = 1;
int amount = 0;
for (int x = lowest + 1; x < operations.size(); x++) {
amount++;
if (operations.get(x) == Operation.OPAREN) {
depth++;
}
if (operations.get(x) == Operation.CPAREN) {
depth--;
if (depth == 0) {
int start = 0;
for (int i = 0; i < lowest; i++) {
if (operations.get(i).takesTwoNumbers()) {
start++;
}
}
List<Operation> insideOperations = new ArrayList<>(operations.subList(lowest + 1, x));
List<Double> insideNumbers = new ArrayList<>(numbers.subList(start, numbers.size()));
double num = evaluate(insideOperations, insideNumbers);
for (int i = 0; i < amount + 1 && lowest < operations.size(); i++) {
if (operations.remove(lowest).takesTwoNumbers()) {
numbers.remove(lowest);
}
}
numbers.set(start, num);
continue stuff;
}
}
}
}
if (operation == Operation.CPAREN) {
return 0;
}
if (operation.takesTwoNumbers()) {
double num = operation.apply(numbers.get(lowest), numbers.get(lowest + 1));
operations.remove(lowest);
numbers.remove(lowest);
numbers.set(lowest, num);
} else {
double num = operation.apply(numbers.get(lowest), 0);
operations.remove(lowest);
numbers.set(lowest, num);
}
}
return numbers.get(0);
}
public static enum Constant {
E("e", Math.E),
PI("pi", Math.PI);
private String name;
private double value;
private Constant(String name, double value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public double getValue() {
return value;
}
}
public static enum Operation {
ADD(null, '+', (a, b) -> a + b, true, 2),
SUBTRACT(null, 'm', (a, b) -> a - b, true, 2),
DIVIDE(null, '/', (a, b) -> a / b, true, 1),
MODULUS(null, '%', (a, b) -> a % b, true, 1),
MULTIPLY(null, '*', (a, b) -> a * b, true, 1),
EXPONENT(null, '^', (a, b) -> Math.pow(a, b), true, 0),
SINE("sin", 's', (a, b) -> Math.sin(a), false, 0),
ASIN("as", 'u', (a, b) -> Math.asin(a), false, 0),
COSINE("cos", 'c', (a, b) -> Math.cos(a), false, 0),
ACOS("ac", 'y', (a, b) -> Math.acos(a), false, 0),
TANGENT("tan", 't', (a, b) -> Math.tan(a), false, 0),
ATAN("at", 'i', (a, b) -> Math.atan(a), false, 0),
RAD("rad", 'r', (a, b) -> Math.toRadians(a), false, 0),
ABS("abs", 'a', (a, b) -> Math.abs(a), false, 0),
LOG("log", 'l', (a, b) -> Math.log10(a), false, 0),
LN("ln", 'n', (a, b) -> Math.log(a), false, 0),
OPAREN(null, '(', (a, b) -> a, false, -2),
CPAREN(null, ')', (a, b) -> a, false, -1);
private String altname;
private char name;
private BiFunction<Double, Double, Double> func;
private boolean twoNumbers;
private int order;
private Operation(String altname, char name, BiFunction<Double, Double, Double> func, boolean twoNumbers, int order) {
this.altname = altname;
this.name = name;
this.func = func;
this.twoNumbers = twoNumbers;
this.order = order;
}
public int getOrder() {
return order;
}
public String getAltName() {
return altname;
}
public char getName() {
return name;
}
public double apply(double num1, double num2) {
return func.apply(num1, num2);
}
public boolean takesTwoNumbers() {
return twoNumbers;
}
public static Operation byName(String name) {
if (name == null || name.length() == 0) {
return null;
}
for (Operation operation : values()) {
if (operation.getName() == name.charAt(0)) {
return operation;
}
}
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment