Hallöchen,
ich möchte diesen Beitrag als eine Art Blog zum Projektfortschritt nutzen. Sollte es eine Blog-Funktion hier geben, habe ich sie nicht gesehen und bitte um den entsprechenden Hinweis. Wenn das doch in ein anderes Forum gehört, bitte verschieben.
Also, worum gehts?
Ich bin hier sicherlich nicht der Erste, der einen Formelparser schreiben will und meiner ist wohl auch nicht der beste aller Formelparser, aber er ist eben meiner . Dieser soll Kern eines Funktionsplotters werden, der später Ableitungen zeichnen kann, Kurvendiskussion, Integrale und und und...
Darum muss der Parser flexibel und auch möglichst performant sein. Folgendes habe ich mir gedacht und zum Teil auch schon umgesetzt:
Der Parser bekommt die Formel als String übergeben, im weiteren Term genannt. Dieser Term wird in seine Bestandteile zerlegt, wie Zahlen, Namen von Konstanten oder Funktionen, Klammern und Operatoren. Diese Elemente speichere ich in einer Liste, aus der sie zur Berechnung abgerufen werden. Das spart schon mal das ständige Neuaufdröseln des Terms bei der Berechnung in einer Schleife.
Vor der Berechnung überprüfe ich, ob für meinen Term Symbole definiert wurden, das sind Konstanten oder die Laufvariable, die vor der Eingabe des Terms vom User angegeben werden können. Wenn es diese Symbole gibt, ersetze ich deren Namen in meiner Liste der Term-Elemente mit den entsprechenden Werten. Gibt es eine Laufvariable, merke ich mir die Indizes in meiner Term-Liste, an denen die vorkommt. So kann ich später dort schnell den neuen Wert eintragen, z.B. bei einem Term wie "4*x^3+3*x^2-2*x+3". Dort gibt es vor der nächsten Berechnung an drei Stellen den aktuellen Wert für das x einzutragen.
Alles, was nach diesem Schritt noch in der Liste steht, sind Zahlen (Double), Operatoren (+, - *, /, ^), Klammern oder Namen von Funktionen, wie Sin oder Cos.
Jetzt macht sich eine Stackmaschine an die Arbeit, welche die Rechenregeln wie Punkt vor Strich und Klammerung kennt. Die Zahlen und Operatoren werden auf einen Variablen- und einen Operatoren-Stack gepusht und nach den Regeln von da abgeholt, ausgerechnet und Zwischenergebnisse wieder auf dem Stack abgelegt.
Das funktioniert inzwischen und wenn der Code vorzeigbar ist, bekommt ihr das im Showroom zum Testen angeboten.
Im Moment bastel ich an der Sache mit den Symbolen, also die zu speichern, zu bearbeiten und in den Term einzutragen.
Frage an die Mathematiker hier wäre, ob die von mir zur Zeit festgelegte Syntax für den Term korrekt ist?
Vorgegeben ist folgendes:
1. Um negative Zahlen immer eine Klammer, also "3*(-2)" statt "3*-2". Die Klammern um einzelne Zahlen entferne ich vor der Berechnung wieder aus der Termliste, aber es macht die Zerlegung des Terms sonst sehr viel komplizierter.
2. Keine implizite Multiplikation. Aus "3Sin(x)" wird der Name "3Sin", wenn dem kein Wert vorher zugewiesen wurde, fällt das irgendwann mit der Fehlermeldung "Unbekannter Operator" auf die Nase, weil dann versucht wird, eine Funktion namens "3Sin" zu berechnen.
3. Auf Funktionsnamen folgt immer eine öffnende Klammer, also "Sin(x)", statt "Sinx". Ihr ahnt es schon, Sinx würde als Name erkannt, wenn es dazu keinen definiertem Wert gibt... siehe Punkt 2.
Soweit ich den Inhalt der letzten Mathevorlesungen vor etwa 30 Jahren noch in Erinnerung habe, ist das korrekt. Sicher mögen sich manche mehr Bequemlichkeit bei der Eingabe wünschen, aber da wird es auch einen Dialog mit Buttons geben, in dem man sich den Term bequem zusammenklicken kann.
Gruß
Carbonunit
ich möchte diesen Beitrag als eine Art Blog zum Projektfortschritt nutzen. Sollte es eine Blog-Funktion hier geben, habe ich sie nicht gesehen und bitte um den entsprechenden Hinweis. Wenn das doch in ein anderes Forum gehört, bitte verschieben.
Also, worum gehts?
Ich bin hier sicherlich nicht der Erste, der einen Formelparser schreiben will und meiner ist wohl auch nicht der beste aller Formelparser, aber er ist eben meiner . Dieser soll Kern eines Funktionsplotters werden, der später Ableitungen zeichnen kann, Kurvendiskussion, Integrale und und und...
Darum muss der Parser flexibel und auch möglichst performant sein. Folgendes habe ich mir gedacht und zum Teil auch schon umgesetzt:
Der Parser bekommt die Formel als String übergeben, im weiteren Term genannt. Dieser Term wird in seine Bestandteile zerlegt, wie Zahlen, Namen von Konstanten oder Funktionen, Klammern und Operatoren. Diese Elemente speichere ich in einer Liste, aus der sie zur Berechnung abgerufen werden. Das spart schon mal das ständige Neuaufdröseln des Terms bei der Berechnung in einer Schleife.
Vor der Berechnung überprüfe ich, ob für meinen Term Symbole definiert wurden, das sind Konstanten oder die Laufvariable, die vor der Eingabe des Terms vom User angegeben werden können. Wenn es diese Symbole gibt, ersetze ich deren Namen in meiner Liste der Term-Elemente mit den entsprechenden Werten. Gibt es eine Laufvariable, merke ich mir die Indizes in meiner Term-Liste, an denen die vorkommt. So kann ich später dort schnell den neuen Wert eintragen, z.B. bei einem Term wie "4*x^3+3*x^2-2*x+3". Dort gibt es vor der nächsten Berechnung an drei Stellen den aktuellen Wert für das x einzutragen.
Alles, was nach diesem Schritt noch in der Liste steht, sind Zahlen (Double), Operatoren (+, - *, /, ^), Klammern oder Namen von Funktionen, wie Sin oder Cos.
Jetzt macht sich eine Stackmaschine an die Arbeit, welche die Rechenregeln wie Punkt vor Strich und Klammerung kennt. Die Zahlen und Operatoren werden auf einen Variablen- und einen Operatoren-Stack gepusht und nach den Regeln von da abgeholt, ausgerechnet und Zwischenergebnisse wieder auf dem Stack abgelegt.
Das funktioniert inzwischen und wenn der Code vorzeigbar ist, bekommt ihr das im Showroom zum Testen angeboten.
Im Moment bastel ich an der Sache mit den Symbolen, also die zu speichern, zu bearbeiten und in den Term einzutragen.
Frage an die Mathematiker hier wäre, ob die von mir zur Zeit festgelegte Syntax für den Term korrekt ist?
Vorgegeben ist folgendes:
1. Um negative Zahlen immer eine Klammer, also "3*(-2)" statt "3*-2". Die Klammern um einzelne Zahlen entferne ich vor der Berechnung wieder aus der Termliste, aber es macht die Zerlegung des Terms sonst sehr viel komplizierter.
2. Keine implizite Multiplikation. Aus "3Sin(x)" wird der Name "3Sin", wenn dem kein Wert vorher zugewiesen wurde, fällt das irgendwann mit der Fehlermeldung "Unbekannter Operator" auf die Nase, weil dann versucht wird, eine Funktion namens "3Sin" zu berechnen.
3. Auf Funktionsnamen folgt immer eine öffnende Klammer, also "Sin(x)", statt "Sinx". Ihr ahnt es schon, Sinx würde als Name erkannt, wenn es dazu keinen definiertem Wert gibt... siehe Punkt 2.
Soweit ich den Inhalt der letzten Mathevorlesungen vor etwa 30 Jahren noch in Erinnerung habe, ist das korrekt. Sicher mögen sich manche mehr Bequemlichkeit bei der Eingabe wünschen, aber da wird es auch einen Dialog mit Buttons geben, in dem man sich den Term bequem zusammenklicken kann.
Gruß
Carbonunit