Formel ausrechnen

  • Antworten:11
Hottemax
  • Forum-Beiträge: 13

16.09.2011, 17:21:28 via Website

Hallo zusammen,

hat mir jemand eine Idee wie ich eine Formel(String) am besten berechnen kann?

Ich möchte in meinem Programm, je nach Auswahl des Benutzers verschiedene Formeln für die Berechnung eines Wertes verwenden. Die Formeln sollen dabei als String hinterlegbar sein.

Als erstes tausche ich nun durch einen Replace die Variablen in meiner Formel durch Werte aus. Und jetzt suche eine Funktion die meinen komplette Formel entgegen nimmt z.B. 3+(4*7) und mir das Ergebnis zurückgibt.

Kennt jemand von euch soetwas?

Gruß

Hottemax

Antworten
Ansgar M
  • Forum-Beiträge: 1.544

16.09.2011, 17:33:28 via Website

Für sowas gibt es Libraries :P Dann muss man es nicht selber machen..
Google führte mich zu "Jep Java" vielleicht findest du ja noch andere, da diese etwas kostet..
Lg Ansgar

Antworten
Maximilian O
  • Forum-Beiträge: 990

20.09.2011, 15:49:30 via Website

Hey Hottemax,
baue dir doch eine eigene Methode, welche dir einen Integer zurückgibt. Den String teilst du einfach zwischen +-*/. Nun ist jeder 2. String ein Rechenzeichen. Jetzt einfach nur noch in einer Schleife die Strings in int's umwandeln und die jeweilige operation, je nach Rechenregel ausführen.
Für die Klammern kannst du das selbe machen, einfach wenn ein String nicht zu einer Zahl geparst werden kann, ist er ein Zeichen.
MfG Maximilian

— geändert am 20.09.2011, 15:49:58

Vergiss nie wieder Geburtstage, oder viel schlimmer, deinen Hochzeitstag - Birthdays Download

Antworten
Hottemax
  • Forum-Beiträge: 13

20.09.2011, 16:15:31 via Website

Hallo Maximilian,

das hatte ich im Prinzip schon so versucht, allerdings bin ich dann bei den Klammern nicht mehr weiter gekommen. Durch die Klammern müßte sich die Reihenfolge in der die einzelnen Zahlen miteinander verrechnet werden ja ändern. D. H. Die innerste Klammer müsste als erstes ausgerechnet werden. Und bisher hatte ich noch keine Idee wie ich das realisieren kann.

Gruß, Hottemax

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

21.09.2011, 00:41:57 via Website

Wenn du keinen richtigen Parser herstellen möchtest, dann gehe wie folgt vor:
1. suche das erste Vorkommen von ")"
2. suche von dort aus rückwärts das erste "("
3. extrahiere diesen Teil und entferne die (dann aussen stehenden) Klammern
4. gib das Ergebnis in den "Simpel-Interpreter", wie ihn Maximilian beschrieben hat
5. füge das Ergebnis an die in 3. gefundene Position ein
6. weiter bei 1.

Wenn 1. kein Ergebnis liefert, gib den Rest in den "Simpel-Interpreter"

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

21.09.2011, 09:38:53 via Website

Das kann man auch mit ner Regex relativ einfach machen.

1String formel = "(1+(2*(3-(4/5))))"
2
3Pattern p = Pattern.compile("\\(([\\d]+)([+*-/]{1})([\\d]+)\\)");
4Matcher m = p.matcher(formel);
5
6if (m.find()) {
7String operand1 = m.group(1);
8String operator = m.group(2);
9String operand2 = m.group(3);
10}

Das findet immer die innerste Klammer zuerst und zerlegt den Ausdruck direkt in die Operanden und den Operator zum Weiterverarbeiten.
Du musst dann lediglich iterativ durchgehen, immer die innerste Klammer ausrechen, in den Orginalstring einsetzen und das Pattern erneut drauf anwenden.

Hinweis:
Diese Regex ist darauf ausgelegt, dass auch der äußerste Teil in Klammern steht, weil explizit darauf gematcht wird.
Damit ist aber sichergestellt, dass man immer alle Stellen der Operanden erwischt.
Man könnte da auch noch ein ODER reinnehmen und auf die gleichen Ausdrücke matchen, die jedoch durch ^ und $ begrenzt sind...das wäre dann einfach Beginn und Ende der Zeile. Dann würde die Regex auch ungeklammerte Ausdrücke erwischen.

Der Vollständigkeit halber ;)
1"\\(([\\d]+)([+*-/]{1})([\\d]+)\\)|^([\\d]+)([+*-/]{1})([\\d]+)$"

— geändert am 21.09.2011, 09:55:43

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

21.09.2011, 23:52:19 via Website

Hm...

Liege ich falsch mit der Behauptung, das dein Pattern an sowas wie
String formel = "(1+(2*(3-(4/5+6))))"
(zwei Operatoren in einer Klammer), oder
String formel = "(1+(2*(3-(4/-5))))"
(Vorzeichen an der 5) scheitern würde?

Bin da ein wenig aus der Übung, daher die Frage ;)

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

22.09.2011, 20:09:44 via Website

Die Anzahl der Permutationen eines Klammerausdruckes ebenfalls, nur leider die maximale Größe einer .apk nicht ;)
Daher ist regex hier wohl nicht das Mittel der Wahl :P

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

23.09.2011, 07:53:24 via Website

Nee mein Lieber.
Jede Formel aus irdischen Zeichen kann man in BNF schreiben, was sich direkt als Summe endlich vieler Regex ausdrücken lässt.
Ich persönlich würde NIE etwas mit primitiven String Operationen machen, was auch über Regex abgewickelt werden kann...umständlich, fehleranfällig und fragil.

— geändert am 23.09.2011, 07:55:47

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

23.09.2011, 11:36:21 via Website

Da ich ja immer gern dazu lerne, skizziere doch mal, wie dein regex aussehen würde, wenn in der Klammerung variabel viele Operatoren stehen dürfen, von mir aus beschränkt auf 0/1/2 Operatoren - und die zugehörige Auswertung (m.group() Formulierungen aus deinem ersten Beispiel).

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

23.09.2011, 11:50:32 via Website

So wie man halt in einer BNF rekursiv die ganze Grammatik von den einfachsten Strukturen nach oben aufbaut, wendest du einfach die Produktionsregeln beim Parsen "rückwärts" an.
Mathematische Formeln sind da noch eine extrem einfache Grammatik.

Du hast NUR Operanden und Zeichen, die diese Operanden gruppieren.
Das können NUR Klammern, oder andere Operatoren, oder Zeilenbeginn und -ende sein.
Da alle einfachen Rechenoperationen binäre Operatoren sind, matcht man auf den simpelst möglichen Ausdruck und ersetzt von innen nach aussen, bis keine weitere Ersetzung möglich ist. Das coole ist ja grade, dass man bei binären Operatoren immer 3 Matching-Groups hat.
Wenn man ganz schlau sein will, wendet man die Regex dann auch noch in einer solchen Reihenfolge an, dass Gesetze wie Punkt- vor Strichrechnung beachtet werden und voila...there we go...wir haben einen Parser für Ausdrücke mit oder ohne Klammern und beliebig vielen Operanden in beliebiger Reihenfolge.

Die einzige elegantere Lösung, die mir da noch einfällt ist ein Syntaxbaum, oder ein Compiler in einer funktionalen Programmiersprache wie Haskell...aber das wäre mit Todessternen auf Spatzen geschossen in dem Fall hier :D

— geändert am 23.09.2011, 11:55:01

Antworten