Formel-Parser und Termberechnung
Projektzusammenfassung | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Mit dem Parser können Rechenausdrücke ausgewertet werden. Der Rechenausdruck wird als String übergeben und kann die in FreeBASIC üblichen Rechenoperationen enthalten:
- Grundrechenarten: +, -, *, /
- Integerdivision \ und Potenz ^
- (runde) Klammern
- Modulorechnung (MOD)
- Bitverschiebung (SHR, SHL)
- die Funktionen SIN, COS, TAN, ASIN, ACOS, ATAN / ATN, ABS, SGN, SQR, EXP, LOG / LN, INT, CINT, FIX und FRAC
Aufgerufen wird der Parser über die Funktion Calculate.eval(evalString), also z. B.
Calculate.eval("2 + 3 * 4 - 1")
Allgemeines
Das Projekt steht unter der MIT-Lizenz.
Quellcode siehe Link ganz unten auf dieser Seite.
Rückmeldungen, Fragen u. ä. bitte im Forum unter http://forum.qbasic.at/viewtopic.php?t=8285#106378.
Einfache Rechenausdrücke
Zahlenwerte werden in der in FreeBASIC üblichen Form übergeben, auch die wissenschaftliche Schreibweise wird unterstützt. Allerdings werden Leerzeichen und Tabulatoren ignoriert und können zur Formatierung eingesetzt werden; einzige Ausnahme ist, dass bei der wissenschaftlichen Schreibweise kein Leerzeichen vor dem "e" stehen darf.
print Calculate.eval("99 999 999 + 1")
Der Rückgabewert ist standardmäßig DOUBLE (dies kann geändert werden, indem vor dem Einbinden der Bibliothek CALCULATE_DATATYPE mithilfe von #DEFINE mit dem gewünschten Datentyp belegt wird).
Tritt ein Fehler auf, so wird der Wert 0 zurückgegeben, außerdem wird die globale Variable Calculate.CalcError gesetzt.
Calculate.NoError = 0
Calculate.ErrorNoValue = 1
Calculate.ErrorMissingBracket = 2
Calculate.ErrorMissingValue = 3
Calculate.ErrorWrongDecimalPoint = 4
Calculate.ErrorWrongExponent = 5
Calculate.ErrorIllegalSymbol = 6
Calculate.ErrorNotANumber = 7
Calculate.ErrorUndefinedFunction = 8
Calculate.ErrorUndefinedVariable = 9
Calculate.ErrorOverwriteFunction = 10
Calculate.ErrorIllegalValue = 11
Bei einem weiteren Aufruf von Calculate.eval wird Calculate.CalcError wieder zurückgesetzt.
Variablen
Der Parser bietet die Möglichkeit, Variablen anzulegen und zu verwenden. Es gibt globale und lokale Variablen - globale Variablen werden mit Calculate.setVar angelegt und stehen für alle weiteren Aufrufe zur Verfügung. Zwei mathematische Konstanten werden gleich zu Beginn als Variablen angelegt:
Calculate.setVar "e", 2.718281828459045
Calculate.setVar "pi", 3.141592653589793
Sie können sofort für Berechnungen verwendet werden:
print Calculate.eval("sin (pi/2)"
Lokale Variablen werden direkt im Evaluationsstring festgelegt und gelten nur für diesen einen Aufruf. Wird eine globale Variable lokal überschrieben, so gilt der neue Wert nur für die Zeit des aktuellen Aufrufs.
Mehrere Anweisungen innerhalb des Evaluationsstrings werden durch Strichpunkt getrennt. Zurückgegeben wird nur der Wert der letzten Anweisung, jedoch können vorherige Anweisungen zur Definition von Variablen dienen.
print Calculate.eval("x=3; x^2")
print Calculate.eval("x=3; y=8-2*x; y^2")
Im letzten Beispiel wird y mit dem Wert 2 belegt; zurückgegeben wird y^2, also 4.
Rekursive Algorithmen
Über die globalen Variablen wäre auch die Umsetzung eines rekursiven Algorithmus möglich, etwa die Nullstellensuche über das Newton-Verfahren, wenn der Term der Funktion und ihrer ersten Ableitungen über die Benutzereingabe erfolgt. Beachte, dass dieses kurze Beispiel keine Abfangroutine für divergente Folgen besitzt!
' Bestimmung von sqr(2) mit dem Newton-Verfahren
dim as string f = "x^2 - 2", fStrich = "2*x"
dim as double x = 1, x2
dim as integer i = 0
print "x0 = " & x
do
i += 1
Calculate.setVar "x", x
x2 = x
x = Calculate.eval("x - (" & f & ")/(" & fStrich & ")")
print "x" & i & " = " & x
loop until abs(x - x2) < .00000001
Es gibt natürlich "schönere" Terme zur Bestimmung von Wurzelwerten, dies soll aber mehr ein Beispiel für die allgemeine Verwendung des Newton-Verfahrens sein.
Bekannte Probleme
Gelegentlich treten bei DOUBLE-Berechnungen Unterschiede im Ergebnis des Parsers und der direkten Berechnung im Programm auf; diese bewegen sich im Bereich der letzten Nachkommastellen und sind durch die mehrfachen Zwischenspeicherungen der einzelnen Teilergebnisse begründet.
Bei "unsinnigen" Rechnungen (etwa Potenzen mit negativer Basis und negativem Exponenten) können ebenfalls unterschiedliche Ergebnisse auftreten.
Sollten weitere Probleme auftauchen, bin ich für Rückmeldungen sehr dankbar!
Dateimanager | ||||
---|---|---|---|---|
|