[英]Simple Java Calculator to Solve Expressions
我正在研究一種可以解決表達式的計算器。 我試圖弄清楚如何使其以PEMDAS順序進行計算。 我有一個用於循環遍歷數組列表的for循環和一個調用執行數學運算的類的開關。 我已經嘗試過if語句,但是還沒有弄清楚。
我該如何更改以確保以正確的順序解決表達式? 這是我到目前為止的內容:
/*
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);
}
}
我認為實現此目標的一個非常標准的算法是Dijkstra的Shunting Yard算法,然后進行后綴評估。 您可以在此處閱讀有關內容,偽代碼在此處,但是您可能需要對基本數據結構有所了解: http : //en.wikipedia.org/wiki/Shunting-yard_algorithm 。
如果您不了解堆棧的,隊列的和后綴的表示法,則可以編寫一個較慢,直接但混亂的實現。 我也用sin,cos,trig,log嘗試了這一遍,並且代碼證明可以正常工作,但是我沒有再嘗試過。
基本上,此想法是僅使用1個運算符來查找優先級最高的表達式,然后對其求值並將其替換。 這是一些偽代碼:
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
請注意,在doMath()
實現中的for循環中,只要看到所有運算符, doMath()
對其求值。 例如,考慮
1 + 2 * 3
您將首先看到+,計算1 + 2,然后將該結果乘以3。相反,您需要首先遍歷整個列表,找到優先級最高的運算符,對其求值,然后再從頭開始。
由於您將其輸入字符串中,為什么不創建一個遍歷每個字符的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;
}
}
以下是解決此問題的幾種可能的設計:
您可以將處理分為兩個部分:解析和評估。 在解析階段,您將字符串轉換為表示如何評估字符串的數據結構。 在評估階段,您將遍歷樹並評估表達式。
您可以按運算符拆分列表,以評估最后一個(正負),評估每個細分(時間和除法)。 如果設計合理,這可能是遞歸的。
第一種選擇更好,因為它可以擴展,但是在實現上也需要更多的努力。 這是通過解析和評估生成的示例數據結構:
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.