Punkt vor Strich in Java Calculator?
WIe kann man die Punkt vor Strich Regel on einem Java Calculator beachten.
3 Antworten
Das hängt davon ab, wie du die Daten eingibst.
An sich ist das nicht allzu trivial. In der Compilerbau-Vorleusng war Punkt-vor-Strich eines der Hautptbeispiele.
Hier ein paar Quellen, die ich gerade dazu fand:
https://www.christian-rehn.de/2010/11/15/se1-kontextfreie-grammatiken/
https://www.spektrum.de/lexikon/mathematik/grammatik/3580
Rein vom Verständnis her:
Stell dir deinen Term als Baum vor, bei dem ein Operator ein Knoten ist und eine Zahl ein Blatt.
Alle Operatoren, die gleichzeitig ausgewertet werden dürfen, liegen auf derselben Ebene im Baum. Der Operator, der als letztes ausgewertet wird ist die Wurzel.
Was du machen möchtest ist einen solchen Baum für einen Term zu erstellen und diesen dann auszuwerten.
Ja, da müsstest du das dann entsprechend parsen.
Bzw. kannst du in dem fall auch abkürzen, so wie ultrarunner das beschreibt.
Du hast dein Endergebnis und dein ZwischenErgebnis.
Solange du Multiplikationen hast multiplizierst du diese zum Zwischenergebnis. Sobald eine Addition kommst addierst du dein Zwischenergebnis auf das Endergebnis.
(Das sollte für Multiplikation und Addition ohne Klammern klappen. Für Subtraktion und Division wird es evtl. komplizierter.)
Das kann man auch mit einem Stack (Stapel) machen. Dieser eignet sich vor allem dann, wenn dein "Calculator" wie ein klassischer Taschenrechner zu bedienen sein soll (und wie dieser auch Zwischenergebnisse anzeigen soll).
Additionen und Subtraktionen werden sofort ausgeführt. Kommt hingegen z.B. ein Malzeichen daher, dann legst du das bisherige Zwischenergebnis samt letztem Rechenzeichen auf den Stapel und beginnst eine neue Rechnung. Wenn dann wieder ein Plus- oder Minuszeichen kommt, holst du den letzten Wert samt Rechenzeichen vom Stapel und führst die jeweilige Operation mit dem Ergebnis der Multiplikation durch.
Auch Operationen mit noch höherem Vorrang (z.B. potenzieren) sowie Klammern kann man mit diesem Stapel behandeln.
Genau. Etwas verallgemeinert kann man auch diesen Ansatz fahren, indem man den ganzen Ausdruck erstmal in RPN umwandelt. Dann ist das Rechnen wirklich simpel, so eine Frage kam auch kürzlich: https://www.gutefrage.net/frage/umgekehrte-polnische-notation-in-java
Oje, mit meiner Antwort habe ich mich wohl unbemerkt geoutet, dass ich RPN-Fan bin. Mein (echter) Taschnenrechner kann natürlich auch nur RPN …
Es wäre übrigens sehr sinnvoll, wenn in der Schule RPN-Rechner verwendet würden. Das würde eine Menge an Verständnisproblemen verhindern.
Das hängt stark von deiner Implementierung ab…
Teile doch mal deinen bisherigen Stand, dann kann man besser weiterhelfen
import java.text.DecimalFormat;
import java.util.Objects;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RunCalculatorTasks {
private static final operators plus = new AdditionOperator();
private static final operators minus = new MinusOperator();
private static final operators multiplie = new MultipieOperator();
private static final operators divide = new DivideOperator();
private static final Scanner sc = new Scanner(System.in);
private static final Pattern somePattern = Pattern.compile("[*/+-]{2,}|^[*/+.]|^-{2,}|\\.{2,}|[A-z,]|[!-)]|\\d\\.[*/+-]|\\.$|[*/+-]{2,}\\s[*/+-]{2,}|\\d+\\.\\d+\\.|/0|/\\s*0|0/|0\\s*/");
private static final DecimalFormat decimalFormat = new DecimalFormat("0.00");
public void input() {
System.out.println("Enter calculation: " + System.lineSeparator());
String entry = sc.nextLine();
checkInput(entry);
}
private boolean validateEntry(String entry) {
Matcher testMatcher = somePattern.matcher(entry);
return !testMatcher.find();
}
private void checkInput(String entry) {
if (entry.startsWith("-")) {
entry = "0" + entry;
}
if (entry.isEmpty() || !validateEntry(entry)) {
System.out.println("That's no valid entry! Please try again.");
input();
} else {
float result = checkOperatorAndCalculate(entry);
System.out.println(decimalFormat.format(result));
}
}
public float checkOperatorAndCalculate(String entry) {
String[] arrOfStr = entry.split("(?=[+\\-*/])|(?<=[+\\-*/])");
for (int iterateThroughArray = 0; iterateThroughArray < arrOfStr.length; iterateThroughArray++) {
if (Objects.equals(arrOfStr[iterateThroughArray], "+")) {
CalculateTask(iterateThroughArray, arrOfStr, plus);
} else if (Objects.equals(arrOfStr[iterateThroughArray], "-")) {
CalculateTask(iterateThroughArray, arrOfStr, minus);
} else if (Objects.equals(arrOfStr[iterateThroughArray], "*")) {
CalculateTask(iterateThroughArray, arrOfStr, multiplie);
} else if (Objects.equals(arrOfStr[iterateThroughArray], "/")) {
CalculateTask(iterateThroughArray, arrOfStr, divide);
}
}
return Float.parseFloat(arrOfStr[arrOfStr.length - 1]);
}
public void CalculateTask( int iterateThroughArray, String[] arrOfStr, operators operators) {
float leftNumber = Float.parseFloat(arrOfStr[iterateThroughArray - 1]);
float rightNumber = Float.parseFloat(arrOfStr[iterateThroughArray + 1]);
float calculatedNumber = operators.calculate(leftNumber, rightNumber);
arrOfStr[iterateThroughArray + 1] = String.valueOf(calculatedNumber);
}
}
Also man kann die Zahlen per UserInput in einer Reihe eingeben. Zb (32*3+1-4).