Frage

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

}
War es hilfreich?

Lösung

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.

Andere Tipps

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

Complete Implementation

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

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:

  • if that text is a number, just append it.
  • if it is an operator add it to the stack.
  • if there was a * or / on the stack perform the calculation and add the new number to the stack.
  • At the end there are only + and - on the stack
  • Calculate the result.

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) + "");
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top