简体   繁体   English

简单的Java计算器来解决表达式

[英]Simple Java Calculator to Solve Expressions

I'm working on an calculator that solves expressions. 我正在研究一种可以解决表达式的计算器。 I'm trying to figure out how to how make it calculate in PEMDAS order. 我试图弄清楚如何使其以PEMDAS顺序进行计算。 I have a for loop to traverse the array list and a switch that calls a class that does the math. 我有一个用于循环遍历数组列表的for循环和一个调用执行数学运算的类的开关。 I've tried if statements, but haven't been able to figure it out. 我已经尝试过if语句,但是还没有弄清楚。

How can I change this to make sure the expression is solved in the proper order? 我该如何更改以确保以正确的顺序解决表达式? Here's what I have so far: 这是我到目前为止的内容:

/*
Peter Harmazinski
Simple Calculator

This program solves expressions
*/

import java.util.*;

public class SimpleCalculator2 {
    static SimpleMath math = new SimpleMath();

    public static void main(String[] args) {
        Scanner console = new Scanner(System.in);
        boolean again = true;
        double number1 = 0.0;
        double number2 = 0.0;
        double answer = 0.0;
        double results = 0.0;
        String delims = "[ ]+";

        getIntroduction();

        while (again) {
            System.out.println("Please enter your expression.");
            String input = console.nextLine();
            System.out.println("This is the user's input: " + input);

            //Parses string into array list
            List<String> list = new ArrayList<String>(Arrays.asList(input.split(delims)));
            System.out.println("list: " + list);

            results = doMath(list, number1, number2);
            getResults(results);
        }
        console.close();
    }

    public static void getIntroduction() {
        System.out.println("This is a simple calculator that solves expressions.");
    }

    //Traverses array list to identify operators and does math for surrounding numbers
    //then answer is inserted in i-1 element and the elements i and i+1 are deleted

    public static double doMath(List<String> list, double number1, double number2) {
        double answer = 0.0;
        double results = 0.0;
        while (list.size() > 1) {
            for (int i = 0; i < list.size(); i++) {
                    switch (list.get(i)) {
                        case "*" :
                            number1 = Double.parseDouble(list.get(i - 1));
                            number2 = Double.parseDouble(list.get(i + 1));
                            answer = math.multiply(number1, number2);
                            System.out.println(answer);
                            list.add(i - 1, Double.toString(answer));
                            list.subList(i, i + 3).clear();
                            System.out.println(list);
                            break;
                        case "/" :
                            number1 = Double.parseDouble(list.get(i - 1));
                            number2 = Double.parseDouble(list.get(i + 1));
                            answer = math.divide(number1, number2);
                            System.out.println(answer);
                            list.add(i - 1, Double.toString(answer));
                            list.subList(i, i + 3).clear();
                            System.out.println(list);
                            break;
                        case "+" :
                            number1 = Double.parseDouble(list.get(i - 1));
                            number2 = Double.parseDouble(list.get(i + 1));
                            answer = math.add(number1, number2);
                            System.out.println(answer);
                            list.add(i - 1, Double.toString(answer));
                            list.subList(i, i + 3).clear();
                            System.out.println(list);
                            break;
                        case "-" :
                            number1 = Double.parseDouble(list.get(i - 1));
                            number2 = Double.parseDouble(list.get(i + 1));
                            answer = math.subtract(number1, number2);
                            System.out.println(answer);
                            list.add(i - 1, Double.toString(answer));
                            list.subList(i, i + 3).clear();
                            System.out.println(list);
                            break;
                        }
                }   
            }   
        return answer;
    }

    public static void getResults(double results) {
        System.out.println("Results are: " + results);
    }
}

I think a pretty standard algorithm to achieve this is Dijkstra's Shunting Yard Algorithm followed by postfix evaluation. 我认为实现此目标的一个非常标准的算法是Dijkstra的Shunting Yard算法,然后进行后缀评估。 You can read about it here, and the pseudocode is here, but you may need to have some understanding of basic data structures: http://en.wikipedia.org/wiki/Shunting-yard_algorithm . 您可以在此处阅读有关内容,伪代码在此处,但是您可能需要对基本数据结构有所了解: http : //en.wikipedia.org/wiki/Shunting-yard_algorithm

If you don't know about stack's, queue's and postfix notation, you could write a slower, straightforward, but messier implementation. 如果您不了解堆栈的,队列的和后缀的表示法,则可以编写一个较慢,直接但混乱的实现。 I tried this one time with sin, cos, trig, log, as well, and the code turned out functional, but not something I would try again. 我也用sin,cos,trig,log尝试了这一遍,并且代码证明可以正常工作,但是我没有再尝试过。

Basically, the idea is to find the highest priority expression with just 1 operator, evaluate it, and replace it with it. 基本上,此想法是仅使用1个运算符来查找优先级最高的表达式,然后对其求值并将其替换。 Here's some pseudocode: 这是一些伪代码:

input = [user input]
while expression still contains (, ), +, -, *, or /:
    toEvaluate = highest priority expression with 1 operator (e.g. 1+2, or 2*3)
    calculate the decimal value of toEvaluate
    modify input so that you replace toEvaluate with its decimal value

Note that in your doMath() implementation, in your for loop, you just evaluate all operators as soon as you see them. 请注意,在doMath()实现中的for循环中,只要看到所有运算符, doMath()对其求值。 For example, consider 例如,考虑

1+2*3 1 + 2 * 3

You will see + first, calculate 1+2 and then multiply that result by 3. Instead, you need to go through the whole list first, find the highest priority operator, evaluate that, then start over from the beginning again. 您将首先看到+,计算1 + 2,然后将该结果乘以3。相反,您需要首先遍历整个列表,找到优先级最高的运算符,对其求值,然后再从头开始。

Since you are entering it into a string why not make a for loop that iterates through every char? 由于您将其输入字符串中,为什么不创建一个遍历每个字符的for循环?

// This for loop will get you the string with only one operator in it.
// EX: 30+32
// You will have to find some way to compute this string.
for(int i = 0; i < userInput.length(); i++)
{
   //int a will be the INDEX of the first operator
   //int b will be the INDEX of the place where a new operator comes up 
   char c = userInput.getCharAt(i);
   a = 0;
   //I'm just gonna do it with + and - for now. Add any other operators.
   if(c == '+' || c == '-')
   {
       b = i;
       String stringToCompute = userInput.substring(a,b);
       //Find some way to take the string there then compute it. 
       //Maybe another for loop with stringToCompute to find where the
       // operator is and then add/subtract the two doubles.  

       // Now reset it 
       a = i;
       b = null;
   }
}

Here are a couple of possible designs to solve this: 以下是解决此问题的几种可能的设计:

  1. You could split the processing into two parts: parsing and evaluating. 您可以将处理分为两个部分:解析和评估。 In the parsing phase you convert the strings to a data structure representing how it will be evaluated. 在解析阶段,您将字符串转换为表示如何评估字符串的数据结构。 In the evaluation phase you traverse the tree and evaluate the expression. 在评估阶段,您将遍历树并评估表达式。

  2. You could split the list by the operators to evaluate last (plus and minus), evaluate each of the segments (times and divide). 您可以按运算符拆分列表,以评估最后一个(正负),评估每个细分(时间和除法)。 This could be recursive if well designed. 如果设计合理,这可能是递归的。

The first option is better as it is more extensible but it is also more effort to implement. 第一种选择更好,因为它可以扩展,但是在实现上也需要更多的努力。 Here is an example data structure to generate via parsing and evaluate: 这是通过解析和评估生成的示例数据结构:

interface Term {
    double getValue();
}

enum Operator {
    MULTIPLY, DIVIDE, ADD, SUBTRACT;
    double getValue(List<Double> operands) {
        ...
    }
}

class Operation implements Term {
    List<Term> operands;
    Operator operator;
    double getValue() {
        return operator.getValue(operands);
    }
}

class Constant implements Term {
    private final double value;
    double getValue() {
        return value;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM