Postfix-Rechner: mehrere math. Operationen nacheinander ausführen

Haave

Top Contributor
Hallo,

ich habe einen kleinen Postfix-Rechner gebastelt, dieser kann beliebig viele Argumente nehmen und an diesen eine einzige mathematische Operation ausführen. Zwei Beispiele:
Code:
java PostfixRechner 3 8 4 7 +
ergibt 22,
Code:
java PostfixRechner 100 4 5 /
ergibt 5 (weil 100/4 = 25, 25/5 = 5).
Das ist der Code für das oben beschriebene, funktionierende Programm:
Java:
class PostfixRechner {
	
	public static void main(String[] args) {
		PostfixRechner kalki = new PostfixRechner();
		System.out.println("Ergebnis: "+kalki.calcMultiArgs(args));
	}
	
	private int result;
	
	public int calcMultiArgs(String[] args) {
		/*Alle Argumente werden ihren zugehoerigen Arrays zugewiesen:
		 *die ints ins eine, die Strings ins andere.
		 *Habe mal gelesen, dass es schwierig sein soll, zu ueberpruefen,
		 *ob etwas ein int ist oder etwas anderes. Darum mache ich es so
		 *mit try/catch. Hoffe, das ist nicht total fail…
		 */
		int[] argsAsInts = new int[args.length];
		String[] operators = new String[args.length];
		for(int i = 0; i < args.length; i++) {
			try {
				argsAsInts[i] = Integer.parseInt(args[i]);
			} catch(NumberFormatException n) {
				operators[i] = args[i];
			}
		}
		//System.out.println("Argumente: "+argsAsInts.length);
		
		//Berechnung
		result = argsAsInts[0]; //weise result den Wert des 1. Args zu, um damit Berechnungen auszufuehren
								//wichtig, da Kommutativgesetz bei Subtraktion & Division nicht gilt
		
		for(int i = 0; i < args.length; i++) {
			if(operators[i] != null) {
				if(operators[i].equals("+")) {
					for(int x = 1; x < i; x++) {
						result += argsAsInts[x];
					}
				} else if(operators[i].equals("-")) {
					for(int x = 1; x < i; x++) {
						result -= argsAsInts[x];
					}
				} else if(operators[i].equals("x")) {
					for(int x = 1; x < i; x++) {
						result *= argsAsInts[x];
					}
				} else if(operators[i].equals("/")) {
					for(int x = 1; x < i; x++) {
						try {
							result /= argsAsInts[x];
						} catch(ArithmeticException a) {
							System.out.println("Division durch 0 ist nicht zulaessig!");
						}
					}
				} else System.out.println("Das eingegebene Zeichen ist kein zulaessiger Operator."); //wird nicht ausgegeben bei "#", warum?
			}
		}
		return result;
	}
}

Nun folgendes:
Ich möchte das Programm dahingehend erweitern, dass es auch mit solchen Eingaben umgehen kann:
Code:
24 3 / 3 +
. Diese Eingabe sollte so rechnen: 24/3 = 8, 8+3 = 11.
Es hängt bei mir daran, dem Programm mitzuteilen, dass es bei allen Operatoren, die nach dem ersten Operator kommen, immer nur bis zum letzten Element vor dem letzten Operator zurückgehen soll. Es soll also bspw. so laufen:
Code:
1 2 3 4 + 3 1 1 -
Programm "guckt" bis Stelle 4 (Stelle d. Plus-Operators) und addiert alle Zahlen auf, bis der Anfang des Argumente-Arrays erreicht wird (Zwischenergebnis: 10). Dann guckt es bis Stelle 8 (Minus-Operator) und zieht von dem bisherigen Zwischenergebnis die gefundenen Zahlen ab (also 10-3-1-1) und hört auf, sobald er zur Stelle kommt, an der er zuvor das Plus fand.

Ich habe da nun schon kräftig rumgefrickelt, aber werde allmählich immer verwirrter… 🙁
Aktueller Code:
Java:
	private java.util.ArrayList<Integer> merkzahl; //NEU: dient zum Speichern der Positionen d. Operatoren
	
	public int calcMultiArgsExtended(String[] args) {
		int[] argsAsInts = new int[args.length];
		String[] operators = new String[args.length];
		java.util.ArrayList<Integer> merkzahl = new java.util.ArrayList<Integer>();
		int y = 0; //fuer den Zugriff auf die Elemente von merkzahl
		for(int i = 0; i < args.length; i++) {
			try {
				argsAsInts[i] = Integer.parseInt(args[i]);
			} catch(NumberFormatException n) {
				operators[i] = args[i];
				merkzahl.add(i); //Position d. Operators wird festgehalten
				System.out.println("Operator an Position "+merkzahl.get(y)); //ACHTUNG: Positionsnummer != Stelle im Array!!
				y++;
			}
		}
		y = 0; //wird wieder 0 gesetzt, um anschliessend damit arbeiten zu koennen
		System.out.println("Argumente: "+argsAsInts.length);
		
		//Berechnung
		//result = argsAsInts[0]; //weise result den Wert des 1. Args zu, um damit Berechnungen auszufuehren
								  //wichtig, da Kommutativgesetz bei Subtraktion & Division nicht gilt
								  //NEU: momentan auskommentiert, um die Addition lauffaehig zu kriegen
		
		for(int i = 0; i < args.length; i++) {
			if(operators[i] != null) {
				if(operators[i].equals("+")) {
					for(int x = 1; merkzahl.get(y)-x > merkzahl.get(y-1) || merkzahl.get(y)-x != 0; x++) { //ich hab mittlerweile den Ueberblick darueber
						result += argsAsInts[merkzahl.get(y)-x];										//verloren, was ich in diesen 2 Zeilen tue :(
						System.out.println("result ist jetzt gerade "+result);
					}
				} else if(operators[i].equals("-")) {
					for(int x = 1; x < i; x++) {
						result -= argsAsInts[x];
					}
				} else if(operators[i].equals("x")) {
					for(int x = 1; x < i; x++) {
						result *= argsAsInts[x];
					}
				} else if(operators[i].equals("/")) {
					for(int x = 1; x < i; x++) {
						try {
							result /= argsAsInts[x];
						} catch(ArithmeticException a) {
							System.out.println("Division durch 0 ist nicht zulaessig!");
						}
					}
				} else System.out.println("Das eingegebene Zeichen ist kein zulaessiger Operator."); //wird nicht ausgegeben bei "#", warum?
				y++;
			}
		}
		return result;
	}

Wahrscheinlich denke ich viel zu kompliziert. Gerade beim Tippen dieses Beitrags kam mir die Idee, erst mal alle eingegebenen Argumente in einen einzigen String zu packen und es dann mit Substrings zu machen… Ehe ich jetzt weiterfrickele: hat von euch jemand eine Idee und kann mir helfen?
 
Alle Zahlen in einen Stack hauen bis ein Zeichen kommt, dann alles mit dem Zeichen verrechneen -> Eine Zahl (lösung) im Stack.
Dann Stack wieder füllen mit Zahlen bis ein Zeichen kommt...verrechnen -> Eine Zahl im Stack
solange bis kein Zeichen mehr kommt --> Eine Zahl im Stack --> Lösung
 
vielleicht so:
Java:
import java.util.LinkedList;
import java.util.Queue;


public class Calc {

	private Queue<Integer> queue = new LinkedList<Integer>();

	private enum Sign {
		PLUS, MINUS;
	}

	public void push(Integer number) {
		queue.add(number);
	}

	public void calc(Sign sign) {
		int result = queue.poll();
		while (!queue.isEmpty()) {
			switch (sign) {
				case PLUS:
					result += queue.poll();
					break;
				case MINUS:
					result -= queue.poll();
					break;
			}
		}
		push(result);
	}

	public int getResult() {
		return queue.peek();
	}

	public static void main(String... _) {
		Calc calc = new Calc();
		// parse some: "1 2 3 + 3 -"
		calc.push(1);
		calc.push(2);
		calc.push(3);
		calc.calc(Sign.PLUS);
		System.out.println(calc.getResult());
		calc.push(3);
		calc.calc(Sign.MINUS);
		System.out.println(calc.getResult());
		calc.push(3);
		calc.calc(Sign.MINUS);
		System.out.println(calc.getResult());
	}
}

EDIT:
eigentlich wäre ne Deque besser und das (Zwischen-) Resultat dann mit getFirst hohlen.
 
Zuletzt bearbeitet:
Hm, die Sache ist etwas kompliziert. Da nicht alle Operatoren explizit genannt werden (z.B. [c]1 2 3 4 5 +[/c] statt [c]1 2 + 3 + 4 + 5 +[/c]), muss man sich was überlegen (z.B. eine Markierung auf den Stack hauen bzw. selbst eingeben).

Denn wofür steht folgende Formel?
1 2 3 4 + *

Deutung 1:
1 * (2 + (3 + 4))

Deutung 2:
1 * (2 * (3 + 4))

Vielleicht habe ich das Problem gerade auch nur völlig falsch verstanden. :bahnhof:

Ark
 
Ich dachte eigentlich, das ist so eine Art primitiver Postfix. dh lese Zahlen bis ein Operator kommt und dann rechne alle Zahlen voher mit dem Operator zusammen.
???:L
 
Danke erst einmal soweit für eure Antworten.

@Der Müde Joe:
Dankeschön für den Denkanstoß, da werde ich wohl mal API und Lehrbuch wälzen müssen, um deinen Code zu verstehen, habe noch keine Erfahrung mit Collections, enums und Zeug auf den Stack tun. Wahrscheinlich habe ich mir da zu viel vorgenommen… 😳

@Ark:
Du bist schon einen Schritt zu weit. Ich habe mich auch schon gefragt, ob Klammerungen ermöglicht werden sollten, fand dann aber, dass ich erst einmal den aktuellen Ansatz lauffähig umsetzen sollte. Ich meinte es so, wie auch Der Müde Joe es offenbar verstanden hat.
 
Soweit ich weiß ist das Hauptargument für die leicht gewöhnungsbedürftige UPN ja gerade, dass man keine Klammern braucht.
 

Zurück
Oben