Reputation: 213
I have the following so far which works fine. Im sure there is probably an easier way to do this but what I will need to change/alter is the top method of Matheq. The Math method does the single math operations.
The it does work with any single operation with +, -, *, and /.
My problem is solving a bigger equation such as 10 - 10 / 5 + 3. It does however solve 10 / 5 + 65 * 2 properly. The reason is that each part, numbers and operations, are split to a string array. After each operation is complete the numbers and operation is replaced with the result of that equation. May seem more confusing but I couldn't think of any better way. The reason why it can't solve the other equation is because of how I mapped the strings back into string array.
Example of string arrays Ex. with 10 - 10 / 5 + 3 String = { 10, -, 10, /, 5, +, 3 } after operations does division first then left to right subtraction then addition String = { 8, 8, 2, 2, 2, 5, 5 }
Here is my code and someone please help me:
REVISED revised, now it works with above but still has some trouble with LONG equations. A short example is that it solves 2 * 2 * 2 * 2 divided by 5 just fine but if change it so 10 - 2 * 2 * 2 * 2 divided by 5 I get wrong answer.
public class Matheq {
String fnum = null;
String lnum = null;
String total = null;
public String Matheq(String mathoperation) {
String mathoperation= "6 * 3 - 4 * 2";
mathoperation = mathoperation.replaceAll(",", "");
mathoperation = mathoperation.replaceAll("plus", "+");
mathoperation = mathoperation.replaceAll("minus", "-");
mathoperation = mathoperation.replaceAll("times", "*");
mathoperation = mathoperation.replaceAll("divided by", "dividedby");
mathoperation = mathoperation.replaceAll("percent of", "percentof");
String[] splitstr = mathoperation.split(" ");
while(splitstr.length>1){
for(int i=0; i<splitstr.length; i++) {
System.out.println("Get value: " + splitstr[i]);
if(splitstr[i].indexOf("percentof") >= 0) {
String buildit = splitstr[i-1] + " percent of " + splitstr[i+1];
String done = math(buildit);
System.out.println("Percentage operation: " + splitstr[i-1] + " percent of " + splitstr[i+1] + "=" + done);
splitstr[i] = done;
splitstr[i-1] = "";
splitstr[i+1] = "";
ArrayList<String> list = new ArrayList<String>();
for(String s : splitstr){
if(!s.equals("")){
list.add(s);
}
}
splitstr = list.toArray(new String[list.size()]);
}
}
for(int i=0; i<splitstr.length; i++) {
System.out.println("Get value: " + splitstr[i]);
if(splitstr[i].indexOf("dividedby") >= 0) {
String buildit = splitstr[i-1] + " divided by " + splitstr[i+1];
String done = math(buildit);
System.out.println("Division operation: " + splitstr[i-1] + " divided by " + splitstr[i+1] + "=" + done);
splitstr[i] = done;
splitstr[i-1] = "";
splitstr[i+1] = "";
ArrayList<String> list = new ArrayList<String>();
for(String s : splitstr){
if(!s.equals("")){
list.add(s);
}
}
splitstr = list.toArray(new String[list.size()]);
}
}
for(int i=0; i<splitstr.length; i++) {
System.out.println("Get value: " + splitstr[i]);
if(splitstr[i].indexOf("*") >= 0) {
String buildit = splitstr[i-1] + " * " + splitstr[i+1];
String done = math(buildit);
System.out.println("Multiplication operation: "+ splitstr[i-1] + " * " + splitstr[i+1] + "=" + done);
splitstr[i] = done;
splitstr[i-1] = "";
splitstr[i+1] = "";
ArrayList<String> list = new ArrayList<String>();
for(String s : splitstr){
if(!s.equals("")){
list.add(s);
}
}
splitstr = list.toArray(new String[list.size()]);
}
}
for(int i=0; i<splitstr.length; i++) {
System.out.println("Get value: " + splitstr[i]);
if(splitstr[i].indexOf("+") >= 0) {
String buildit = splitstr[i-1] + " + " + splitstr[i+1];
String done = math(buildit);
System.out.println("Addition operation: " + splitstr[i-1] + " + " + splitstr[i+1] + "=" + done);
splitstr[i] = done;
splitstr[i-1] = "";
splitstr[i+1] = "";
ArrayList<String> list = new ArrayList<String>();
for(String s : splitstr){
if(!s.equals("")){
list.add(s);
}
}
splitstr = list.toArray(new String[list.size()]);
}
}
for(int i=0; i<splitstr.length; i++) {
System.out.println("Get value: " + splitstr[i]);
if(splitstr[i].indexOf("-") >= 0) {
String buildit = splitstr[i-1] + " - " + splitstr[i+1];
String done = math(buildit);
System.out.println("Subtraction operation: " + splitstr[i-1] + " - " + splitstr[i+1] + "=" + done);
splitstr[i] = done;
splitstr[i-1] = "";
splitstr[i+1] = "";
ArrayList<String> list = new ArrayList<String>();
for(String s : splitstr){
if(!s.equals("")){
list.add(s);
}
}
splitstr = list.toArray(new String[list.size()]);
}
}
for(int i=0; i<splitstr.length; i++) {
System.out.println("Final operation: " + total + " " + splitstr[i]);
}
}
return total;
}
private String math(String mathoperation) {
// TODO Auto-generated method stub
if(mathoperation.contains("percent of")){
mathoperation = mathoperation.replaceAll("percent of", "%");
int str = mathoperation.indexOf("%");
System.out.println(str);
fnum = mathoperation.substring(0, str-1);
fnum = fnum.replaceAll(" ", "");
fnum = "." + fnum;
System.out.println(fnum);
double intfnum = Double.parseDouble(fnum);
System.out.println(intfnum);
int lastind = mathoperation.length();
System.out.println(lastind);
lnum = mathoperation.substring(str+1, lastind);
lnum = lnum.replaceAll(" ", "");
System.out.println(lnum);
double intlnum = Double.parseDouble(lnum);
System.out.println(intlnum);
double tot = intlnum * intfnum;
System.out.println(tot);
total = Double.toString(tot);
if(total.length() == 3){
total = total + "0";
}
if(total.length() > 5){
total = total.substring(0, 4);
}
total = total.replace("0.", "");
System.out.println("Total:" + total);
} else
if(mathoperation.contains("-")){
int str = mathoperation.indexOf("-");
System.out.println(str);
fnum = mathoperation.substring(0, str-1);
fnum = fnum.replaceAll(" ", "");
System.out.println(fnum);
double intfnum = Double.parseDouble(fnum);
System.out.println(intfnum);
int lastind = mathoperation.length();
System.out.println(lastind);
lnum = mathoperation.substring(str+1, lastind);
lnum = lnum.replaceAll(" ", "");
System.out.println(lnum);
double intlnum = Double.parseDouble(lnum);
System.out.println(intlnum);
double tot = intfnum - intlnum;
System.out.println(tot);
total = Double.toString(tot);
System.out.println(total);
} else
if(mathoperation.contains("+")){
int str = mathoperation.indexOf("+");
System.out.println(str);
fnum = mathoperation.substring(0, str-1);
fnum = fnum.replaceAll(" ", "");
System.out.println(fnum);
double intfnum = Double.parseDouble(fnum);
System.out.println(intfnum);
int lastind = mathoperation.length();
System.out.println(lastind);
lnum = mathoperation.substring(str+1, lastind);
lnum = lnum.replaceAll(" ", "");
System.out.println(lnum);
double intlnum = Double.parseDouble(lnum);
System.out.println(intlnum);
double tot = intfnum + intlnum;
System.out.println(tot);
total = Double.toString(tot);
System.out.println(total);
} else
if(mathoperation.contains("*")){
int str = mathoperation.indexOf("*");
System.out.println(str);
fnum = mathoperation.substring(0, str-1);
fnum = fnum.replaceAll(" ", "");
System.out.println(fnum);
double intfnum = Double.parseDouble(fnum);
System.out.println(intfnum);
int lastind = mathoperation.length();
System.out.println(lastind);
lnum = mathoperation.substring(str+1, lastind);
lnum = lnum.replaceAll(" ", "");
System.out.println(lnum);
double intlnum = Double.parseDouble(lnum);
System.out.println(intlnum);
double tot = intfnum * intlnum;
System.out.println(tot);
total = Double.toString(tot);
System.out.println(total);
} else
if(mathoperation.contains("divided by")){
mathoperation = mathoperation.replaceAll("divided by", "/");
int str = mathoperation.indexOf("/");
System.out.println(str);
fnum = mathoperation.substring(0, str-1);
fnum = fnum.replaceAll(" ", "");
System.out.println(fnum);
double intfnum = Double.parseDouble(fnum);
System.out.println(intfnum);
int lastind = mathoperation.length();
System.out.println(lastind);
lnum = mathoperation.substring(str+1, lastind);
lnum = lnum.replaceAll(" ", "");
System.out.println(lnum);
double intlnum = Double.parseDouble(lnum);
System.out.println(intlnum);
double tot = intfnum / intlnum;
System.out.println(tot);
total = Double.toString(tot);
System.out.println(total);
} else {
total = null;
}
return total;
}
}
Upvotes: 4
Views: 40249
Reputation: 1034
I didn't make the dot working, that's for another day.
in the main
or launch
let the buttons send their text to our buttonHandler.
buttons.get(i).setOnAction(ev -> buttonHandler(text))
In the method:
The code:
private void buttonHandler(String buttonValue) {
String newInput = tfInput.getText();
switch (buttonValue) {
default:
// If a previous calculation was made, reset input.
if (lastOperator.equals("=")) {
lInput.setText("");
tfInput.setText(buttonValue);
// else append the new input.
} else {
tfInput.appendText(buttonValue);
}
break;
case " ":
break;
case ".":
if(!input.contains(".")) {
tfInput.appendText(buttonValue);
}
break;
case "DEL":
try {
tfInput.setText("" + newInput.substring(0, tfInput.getText().length() - 1));
} catch (Exception ex) { }
break;
// Operators
case "x":
case "/":
case "+":
case "-":
case "=":
if (newInput.length() > 0) {
lInput.setText(lInput.getText() + newInput + " " + buttonValue + " ");
try {
// If the previous operator has priority, make a calculation and push to stack
if (!input.empty()) {
if (input.peek().equals("x")) {
input.pop();
newInput = new BigDecimal(input.pop()).multiply(new BigDecimal(newInput)).toString();
} else if (input.peek().equals("/")) {
input.pop();
newInput = new BigDecimal(input.pop()).divide(new BigDecimal(newInput), 3, RoundingMode.HALF_UP).stripTrailingZeros().toString();
System.out.println(newInput);
}
}
} catch (Exception ex) {
System.out.println("something is this part went wrong");
}
// If the "=" wasn't pressed, add input to the stack and set the textfield empty.
if (!buttonValue.equals("=")) {
// Push to stack and empty input.
input.push(newInput);
input.push(buttonValue);
tfInput.setText("");
// The button is "=". Prepare for final calculation
} else {
if(!input.empty()) {
try {
// Reverse items.
Stack<String> stack = new Stack<>();
stack.push(newInput);
while (!input.empty()) {
stack.push(input.pop());
}
// Perform final calculation.
while (!stack.empty()) {
String firstNumber = stack.pop();
if (stack.peek().equals("+")) {
stack.pop();
newInput = new BigDecimal(firstNumber).add(new BigDecimal(stack.pop())).toString();
} else if (stack.peek().equals("-")) {
stack.pop();
newInput = new BigDecimal(firstNumber).subtract(new BigDecimal(stack.pop())).toString();
}
if (!stack.empty()) {
stack.push(newInput);
} else {
tfInput.setText(newInput);
}
}
} catch (Exception ex) {
System.out.println("something in the second part went wrong");
}
} else {
tfInput.setText(newInput);
}
}
}
}
lastOperator = buttonValue;
}
if you want to calculate a string put something like this in the 'launch' mehtod:
String test = "10-10/5+3=";
for (int i = 0; i < test.length(); i++) {
buttonHandler(test.charAt(i) + "");
}
Upvotes: 0
Reputation: 66
All you have to do is convert the prefix input into postfix format. Then you can easily do the magic using an stack. I have used the command pattern to write a complete solution.
Method to convert infix to postfix
public static List<String> infixToPostfixConvert(String input) {
int priority = 0;
String postfixBuffer = "";
Stack<Character> stack = new Stack<Character>();
List<String> postfixArray = new ArrayList<String>();
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
if (postfixBuffer.length() > 0) {
postfixArray.add(postfixBuffer);
}
postfixBuffer = "";
// check the precedence
if (stack.size() <= 0)
stack.push(ch);
else {
Character chTop = (Character) stack.peek();
if (chTop == '*' || chTop == '/')
priority = 1;
else
priority = 0;
if (priority == 1) {
if (ch == '+' || ch == '-') {
postfixArray.add(String.valueOf(stack.pop()));
i--;
} else { // Same
postfixArray.add(String.valueOf(stack.pop()));
i--;
}
} else {
if (ch == '+' || ch == '-') {
postfixArray.add(String.valueOf(stack.pop()));
stack.push(ch);
} else
stack.push(ch);
}
}
} else {
postfixBuffer += ch;
}
}
postfixArray.add(postfixBuffer);
int len = stack.size();
for (int j = 0; j < len; j++)
postfixArray.add(stack.pop().toString());
return postfixArray;
}
Then i have another method that uses Calculator instance and pass the postfix string.
public void calculate(Calculator cal, List<String> postFix) {
Stack<BigDecimal> stack = new Stack<BigDecimal>();
for ( int i = 0; i < postFix.size(); i++ ) {
String next = postFix.get(i);
if (next.equals("+") || next.equals("-") || next.equals("*")
|| next.equals("/")) {
ArithmaticCalculatorCommand cmd = new ArithmaticCalculatorCommand(
next.charAt(0), stack.pop(), stack.pop(), cal);
Invoker invoker = new Invoker();
invoker.compute(cmd);
stack.push(cal.getCurrent());
} else if ( false ){
}
else
{
stack.push(new BigDecimal(next.trim()));
}
}
}
command Interface
package org.sanjaya;
public interface Command {
public void calculate();
}
Command implementation
package org.sanjaya.impl;
import java.math.BigDecimal;
import org.sanjaya.Command;
public class ArithmaticCalculatorCommand implements Command {
private char operator;
private BigDecimal leftOperand;
private BigDecimal rightOperand;
private Calculator calculator;
public ArithmaticCalculatorCommand( char operator, BigDecimal leftOperand, BigDecimal rightOperand, Calculator calculator ) {
this.leftOperand = leftOperand;
this.rightOperand = rightOperand;
this.operator = operator;
this.calculator = calculator;
}
/*
* This method invoke the three argument operation method that is only used for arithmetic calculations.
* @param operator
* @param leftOperand
* @param rightOperand *
* @see org.sanjaya.Command#calculate()
*/
public void calculate() {
calculator.operation( operator, leftOperand, rightOperand );
}
}
Calculator Class( Reciever)
package org.sanjaya.impl;
import java.math.BigDecimal;
public class Calculator {
private static Calculator calculator;
private BigDecimal current = new BigDecimal( 0 );
private Calculator()
{
}
public static Calculator getInstance()
{
if ( calculator == null )
{
calculator = new Calculator();
}
return calculator;
}
/*
* This method calculate current value for any number of calculation operations.
* Currently following operations are supported
* +,-,*,/
*
* @param operator
* @param leftOperand
* @param rightOperand
*
*/
public void operation( char operator, BigDecimal leftOperand, BigDecimal rightOperand )
{
switch ( operator )
{
case '+':
current = leftOperand.add( rightOperand );
break;
case '-':
current = rightOperand.subtract( leftOperand );
break;
case '/':
current = rightOperand.divide(leftOperand);
break;
case '*':
current = leftOperand.multiply( rightOperand );
break;
default:
break;
}
}
public BigDecimal getCurrent() {
return current;
}
public void setCurrent(BigDecimal current) {
this.current = current;
}
}
Invoker Class
package org.sanjaya.impl;
import java.math.BigDecimal;
import org.sanjaya.Command;
public class Invoker {
public void compute( Command command )
{
command.calculate();
}
}
Client Class
package org.sanjaya.impl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
import java.util.logging.Logger;
public class CalculatorParser {
public static Logger logger = Logger.getLogger( "Calculator_Logger" );
public static void main( String a [] )
{
new CalculatorParser().start();
}
/*
* This is the starting point of the program. It receives input from the command line
* and process them further and sends to calculate function. At the end this method
* displays the calculated result.
*/
public void start()
{
Scanner scanner = new Scanner( System.in );
logger.info("\n\t Please input expression to calculate::");
String line = scanner.nextLine();
List<String> postfixString = CalculatorParser.infixToPostfixConvert( line );
Calculator calculator = Calculator.getInstance();
calculator.setCurrent( new BigDecimal( 0 ) );
calculate( calculator, postfixString );
logger.info("Result is " + calculator.getCurrent() );
}
/*
* This method keeps a stack to process postfix version of the input and execute the right command implementation.
* Currently this method supports for arithmetic command calculations only.
* @param Cal
* @param postFix
*/
public void calculate(Calculator cal, List<String> postFix) {
Stack<BigDecimal> stack = new Stack<BigDecimal>();
for ( int i = 0; i < postFix.size(); i++ ) {
String next = postFix.get(i);
if (next.equals("+") || next.equals("-") || next.equals("*")
|| next.equals("/")) {
ArithmaticCalculatorCommand cmd = new ArithmaticCalculatorCommand(
next.charAt(0), stack.pop(), stack.pop(), cal);
Invoker invoker = new Invoker();
invoker.compute(cmd);
stack.push(cal.getCurrent());
} else if ( false ){
}
else
{
stack.push(new BigDecimal(next.trim()));
}
}
}
/*
* This method convert the infix into postfix in order to proceed in the calculation.
* @param input
*/
public static List<String> infixToPostfixConvert(String input) {
int priority = 0;
String postfixBuffer = "";
Stack<Character> stack = new Stack<Character>();
List<String> postfixArray = new ArrayList<String>();
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
if (postfixBuffer.length() > 0) {
postfixArray.add(postfixBuffer);
}
postfixBuffer = "";
// check the precedence
if (stack.size() <= 0)
stack.push(ch);
else {
Character chTop = (Character) stack.peek();
if (chTop == '*' || chTop == '/')
priority = 1;
else
priority = 0;
if (priority == 1) {
if (ch == '+' || ch == '-') {
postfixArray.add(String.valueOf(stack.pop()));
i--;
} else { // Same
postfixArray.add(String.valueOf(stack.pop()));
i--;
}
} else {
if (ch == '+' || ch == '-') {
postfixArray.add(String.valueOf(stack.pop()));
stack.push(ch);
} else
stack.push(ch);
}
}
} else {
postfixBuffer += ch;
}
}
postfixArray.add(postfixBuffer);
int len = stack.size();
for (int j = 0; j < len; j++)
postfixArray.add(stack.pop().toString());
return postfixArray;
}
}
Upvotes: 4
Reputation: 14388
An array is the wrong structure to represent the parsed equation. You need to have a structure that can represent the operator precedence. The typical mechanism for handling this type of problem is an abstract syntax tree. For your 10 - 10 / 5 + 3 example you would probably want to build a tree that looks like this:
<result>
/ \
'-' '+'
/ \ / \
10 '/' 3
/ \
10 5
With this type of structure with the high precedence operators lower down the tree, then you can perform a bottom up evaluation to get the correct result.
Upvotes: 9