← ST-Computer 02 / 1987

Formelberechnung mit GfA-BASIC

Grundlagen

Oft findet man in Computerzeitschriften und -büchern Programme in allen möglichen Sprachen, die Berechnungen oder graphische Darstellungen mit mathematischen Funktionen durchführen. Meist sind jedoch die Formeln fest im Programm „eingebaut“, und Änderungen können zum Teil mit erheblichem Aufwand verbunden sein, insbesondere wenn man mit Compilern arbeitet.

Wer mit einem BASIC-Interpreter herkömmlicher Art arbeitet, der über die Befehle CHAIN und MERGE verfügt, kann sich mit einem Trick aus der Patsche helfen. Wie in Listing 1 gezeigt ist es möglich, über den Umweg einer Diskettendatei ein sich selbst veränderndes Programm zu schreiben.

Programmiert man jedoch in einer Compilersprache oder z. B. mit dem enorm leistungsfähigen GfA-BASIC-Interpreter, kommt man mit solchen Kniffen nicht mehr weiter.

Hier hilft alles nichts, man muß sich sozusagen zu Fuß durch eine als Zeichenkette eingegebene Formel „beißen“ und Zeichen für Zeichen analysieren.

So aufwendig, wie das auf den ersten Blick scheinen mag, ist dies nun auch wieder nicht; das Zauberwort, das hier weiterhilft heißt Rekursion.

Schauen wir uns doch einmal eine Formel - einen arithmetischen Ausdruck wie die Mathematiker sagen - genauer an. Zur graphischen Verdeutlichung sollen hier sogenannte Syntax-Diagramme, ähnlich wie man sie zur Definition von PASCAL-Befehlen verwendet, weiterhelfen. Bild 1 erklärt die möglichen Symbole. Syntax-Diagramme werden in Pfeilrichtung auf Flußlinien durchlaufen; diese können sich an verschiedenen Stellen aufspalten und so Möglichkeiten zur Verzweigung und Schleifenbildung beschreiben. Die Kästchen mit den abgerundeten Ecken dienen nur der Namensgebung des jeweiligen Diagramms und können einfach übergangen werden.

Bild 1: Definition der für die Syntax-Diagramme verwendeten Symbole

Unsere Formel kann nun als Kette von Zeichen, die sich in bestimmte Teilketten zerlegen läßt, mit diesem Schema formal beschrieben werden.

So, wie man den arithmetischen Ausdruck von links nach rechts zu Papier bringt, kann man den Flußlinien folgen und, gemäß der mathematischen Hierarchie der Rechenregeln, von einer Grobdarstellung zu immer weiteren Unterteilungen gelangen.

Wohlgemerkt, Syntax-Diagramme sind weder Flußdiagramme noch dienen sie zur exakten Darstellung eines Programmablaufs, jedoch lassen sich die durch sie beschriebenen Regeln leicht in entsprechende Programm-Algorithmen umsetzen.

Bild 2

In Bild 2 ist nun allgemein ein arithmetischer Ausdruck dargestellt, der aus beliebig vielen einfachen Ausdrücken besteht, die über das Plus- oder Minuszeichen verknüpft sein können. Dies ist durch die Abzweigung hinter dem Käsen „Einfacher Ausdruck“ verdeutlicht, was bedeutet, daß hier abgebogen wird solange einem Teilausdruck ein Plus- oder Minusoperator folgt.

Beispiel:

6.89 + (3/7.8-5)*5 - sin(exp(-3*7/8)) + ...

6.89, (3/7.8 - 5)5, sin(exp(-37/8)) sind Teilausdrücke des o. g. arithmetischen Audrucks

Jeder einfache Ausdruck setzt sich aus einzelnen Termen zusammen, die über Multiplikation oder Division verknüpft sind (Bild 3).

Bild 3

Ein Term ist ein vorzeichenbehafteter Faktor, der gegebenenfalls wiederum mit einem vorzeichenbehafteten Faktor potenziert sein kann (Bild 4).

Bild 4

Ein vorzeichenbehafteter Faktor besteht aus einem vorzeichenlosen (positiven) Faktor mit eventuell vorangestelltem negativem Vorzeichen (Bild 5).

Wie in Bild 6 zu sehen, ist nun ein Faktor entweder eine positive reelle Zahl (die sich aus Ziffern, eventuell Dezimalpunkt und/oder Exponent zusammensetzt), ein in Klammern stehender arithmetischer Ausdruck, eine Variable (hier als „x“ bezeichnet) oder eine mathematische Funktion, deren Argument selbst wieder ein Faktor ist.

Listing 2 zeigt ein GfA-BASIC Programm, welches das Modul FORMEL. MRG enthält. Hier wird gezeigt, wie sich konsequent oben genannte Regeln ine ine Hochsprache umsetzen lassen. GfA-BASIC ist hierzu ebenso geeignet wie PASCAL oder C. Eine Umsetzung des Moduls in eine dieser Sprachen sollte daher keine Probleme bereiten. Bei FORMEL.MRG handelt es sich um ein universell benutzbares Teilprogramm, das leicht an unterschiedliche Anwendungen angepaßt werden kann.

Das eigentliche Hauptprogramm mit der Procedure Def_funktion dient nur der Demonstration von FORMEL.MRG. Das hier vorgestellte Modul kann sehr vielseitig verwendet werden, z. B. für einen selbstprogrammierten Taschenrechner, ein Funktionsplotprogramm oder die Analyse von mathematischen Funktionen. Erweiterungen mit beliebig komplexen Funktionen sind leicht durchzuführen, wie im Programmtext an entsprechender Stelle kommentiert wurde.

Ich hoffe, FORMEL.MRG gibt viele Anregungen für eigene Ideen und wünsche viel Spaß beim Programmieren.

(H. Bauch)

Bild 5
'**************************************************** '* * '* --- ST_FORM.BAS --- * '* Beispiel zur Berechnung beliebiger Formeln * '* mit dem ST-BASIC-Interpreter * '* * '* (c) 22.11.1986 H. Bauch * '* * '**************************************************** Clearw 2:Fullw 2 Print Print " F O R M E L B E R E C H N U N G " Print " ---------------------------------" Print gosub Funktion.def ' Anfang: Input " x = ",xS If x$<>"N" and x$<>"n" Then Print " f(x) = ";fny(val(x$)),"<N> für neue Funktion !" Else Gosub Funktion.def Goto Anfang ' ' Funktion.def: Print Print " Definition einer beliebigen Funktion in BASIC-Syntax" Print Input " f(x) = ",Formel$ Open "O",#1,"FKT.BAS" Print#1,"200 Def fny(x) = "+Formel$ Close #1 Chain Merge "FKT.BAS",200 ' Die nächste Zeile wird vom Programm verändert: Def fny(x) = 1/(sqr(1-x^2)) Return ' *********************************************************** ' * * ' * -- FORMULA.BAS -- * ' * Ein Testprogramm für das Modul FORMEL.MRG * ' * * ' * (c) 23.11.1936 H. Bauch * ' * Taunusstr. 96 * ' * 6237 Liederbach * ' * * ' *********************************************************** ' ' --- Konscantendefinitionen ' True:=-1 False!=0 ' ' ' ---------------------------------------------------------------- ' ---------- Beginn des Hauptprogramms zum ----------------------- ' ---------- Testen des Moduls FORMEL.MRG: ----------------------- ' ---------------------------------------------------------------- ' Cls Print Print Print " F O R M E L B E R E C H N U N G " Print " ---------------------------------" Print Print " (c) 1986 H. Bauch" Print First!=True!$ @Def_funktion ' Do Input " x = ",X$ If Val?(X$)<>0 X=Val(X$) @Berechnung(Formel$,X) Print " f(x) = ";Berechnung, Print "Für neue Funkion <N> eingeben !" Print Else If Upper$(X$)="N" @Def_funktion Endif Endif Loop ' ' ------------------------------------------------------- ' ------------- Ende des Hauptprogramms ----------------- ' ------------------------------------------------------- ' ' Procedure Def_funktion ' ' ---------------------------------------------------------------- ' Dieses Unterprogramm dient nur zu Testzwecken; es ermöglicht ' erstmaliges und wiederholtes Definieren einer Formel/Funktion in ' Form eines Strings. Funktionen können auch konstant sein, d. h. ' es kommt keine Variable (hier "x") in ihr vor. ' ---------------------------------------------------------------- ' ' Globale Variable: True!,False!,First!,F_max%,Std_funktion$(), ' Formel$, Fehler_positon% Local I%,Xtest,Fehleraus$ ' If First! @Init_berechnung First!=False! Print Print " Definition einer beliebiger. Funktion in BASIC-Syntax" Print Print " Standardfunktionen: " Print Print " / "; For I%=1 To F_max% Print Std_funktion$(1%);" / "; Next I% Endif Print Print Repeat Input " f(x) = ",Formel$ ' ----------------------------------------------------------------- ' An dieser Stelle wird die @Berechnung() zunächst mit einem Test- ' wert aufgerufen; in einigen Fällen kann es bei dem hier gewählten ' Wert zum Fehlerabbruch kommen, weil sich z. B- Division durch ' Null oder Wurzel aus negativer Zahl ergibt. ' Ein einfacher Syntaxfehler wird so jedoch aufgedeckt. ' ----------------------------------------------------------------- Xtest=0.0123 @Berechnung(Formel$,Xtest) If (Fehler_position%<>0) Fehleraus$="Fehler in der Formel!an Position "+Str$(Fehler_position%) Alert 1,Fehleraus$,1," Weiter ", Dummy Endif Until (Fehler_position%=0) Return ' ' ' *********************************************************** ' * * ' * --- FORMEL.MRG--- * ' * Berechnung einer beliebigen Funktion als String * ' * * ' *********************************************************** ' Procedure Init_berechnung ' ' ------------------------------------------------------------------ ' Dieses Unterprogramm dient zur Initialisierung der benutzbaren ' Standardfunktionen für die Procedure Faktor; Erweiterungen können ' dort leicht eingefügt werden, Funktionsnamen müssen in der DATA- ' Zeile ergänzt werden und F_max% muß angepaßt werden. ' Init_berechnung muß stets vor der Procedure Berechnung aufgerufen ' werden. ' ------------------------------------------------------------------ ' ' Globale Variable: F_max%, ' Std_funktion$() Local I% ' ' Anzahl z.Zt. implementierter Standardfunktionen: F_max%=9 ' ' Standardfunktionen festlegen Dim Std_funktion$(F_max%) Data ABS,SQR,SIN,COS,TAN,ATN,LN,LOG,EXP Restore For I%=1 To F_max% Read Std_funktion$(I%) Next I% Return ' ' Procedure Berechnung(Funktion$,X) ' ' ------------------------------------------------------------------ ' Dies ist die Hauptroutine des Moduls FORMEL.MRG; nach Aufruf von ' von Init_berechnung wird stets hier eingesprungen. In einem Haupt- ' programm können verschiedene Formeln benötigt werden; diese werden ' einfach jeweils neu durch den Stringparameter Funktion$ übergeben. ' Z. Zt. ist nur eine Variable (X) in der Procedure Faktor vorge- ' sehen, Erweiterungen auf beliebig viele Variable sind möglich ' durch Ergänzung der Parameterliste und Erweiterung der Procedure ' Faktor an der dort bezeichneten Stelle. ' ' Sollte in Funktion$ ein Syntax-Fehler gefunden werden, so wird ' Fehler position% als Global zurückgegeben. ' ' ' Da GfA-BASIC keine Function im Sinne von PASCAL besitzt, werden die ' Ergebnisse einer Procedure als Variable mit dem Namen der Proce- ' dure zurückgegeben. ' ------------------------------------------------------------------ ' ' Globale Variable: True!, False!, F_max%, Berechnung, Fehler_position% ' Std_funktion$(), Berechnung ' Local Zeil_ende$,Position,Zei$,Ausdruck ' Zeil_ende$=Chr$(0) Position%=0 @N_zeichen @Ausdruck Berechnung=Ausdruck If Zei$=Zeil_ende$ Fehler_position%=0 Else Fehler_position%=Position% Endif Return ' ' Procedure Ausdruck ' Local E,Einf_ausdruck,Operator$ ' @Einf_ausdruck E=Einf_ausdruck While Zei$="+" Or Zei$="-" Operator$=Zei$ @N_zeichen If Operator$="+" @Einf_ausdruck E=E+Einf_ausdruck Endif If Operator$="-" @Einf_ausdruck E=E-Einf_ausdruck Endif Wend Ausdruck=E Return ' ' Procedure Einf_ausdruck ' Local S,Term,Operator$ ' @Term S=Term While Zei$="*" Or Zei$="/" Operator$=Zei$ @N_zeichen If Operator$="*" @Term S=S*Term Endif If Operator$="/" @Term S=S/Term Endif Wend Einf_ausdruck=S Return ' ' Procedure Term ' Local T,Vorz_faktor @Vorz_faktor T=Vorz_faktor While Zei$="*" @N_zeichen @Vorz_faktor T=T^Vorz_faktor Wend Term=T Return ' ' Procedure Vorz_faktor ' Local Faktor ' If Zei$="-" @N_zeichen @Faktor Vorz_faktor=-Faktor Else @Faktor Vorz_faktor=Faktor Endif Return ' ' Procedure Faktor ' Local F,I%,L%,Beginn% ' If Zei$>="0" And Zei$<="9" ' -------------------------------------------------------- ' "Zusammenbasteln" einer Zahlen-Konstante ' -------------------------------------------------------- Beginn%=Position% Repeat @N_zeichen Until Not (Zei$>-"0" And Zei$<="9") If Zei$="." Repeat @N_zeichen Until Not (Zei$>="0" And Zei$<="9") Endif If Upper$(Zei$)="E" @N_zeichen Repeat @N_zeichen Until Not (Zei$>="0" And Zei$<="9") Endif F=Val(Mid$(Funktion$,Beginn%,Position%-Beginn%)) Else If Zei$="(" ' ---------------------------------------------------- ' Faktor ist ein geklammerter Ausdruck, d.h. ' rekursiver Aufruf der Procedure Ausdruck ' ---------------------------------------------------- @N_zeichen @Ausdruck F=Ausdruck If Zei$=")" @N_zeichen Else Fehler_position%=Position% Endif Else If Upper$(Zei$)="X" ' ----------------------------------------------------- ' Variable der Formel gefunden! ' Hier können Erweiterungen für beliebig viele Variable ' "eingebaut" werden; siehe auch Kommentar zu Beginn der ' Hauptroutine Procedure Berechnung(). ' ----------------------------------------------------- @N_zeichen F=X Else ' ----------------------------------------------------------- ' Suche nach Standardfunktions-Namen wie bei ' Procedure Init_Berechnung in der Data-Zeile vereinbart! ' Hier können noch beliebig viele Funktionen ergänzt werden ' (z.B. arcsin, arccos, Fakultit, hyperbol. Funktion usw.). ' ----------------------------------------------------------- Erfolg!=False! For I%=1 To F_max% If Erfolg!=False! L%=Len(Std_funktion$(1%)) If Upper$(Mid$(Funktion$,Position%,L%))=Std_funktion$(1%) Position%=Position%+L%-1 @N_zeichen @Faktor F=Faktor If I%=1 F=Abs(F) Endif If I%=2 F=Sqr(F) Endif If I%=3 F=Sin(F) Endif If I%=4 F=Cos(F) Endif If I%=5 F=Tan(F) Endif If I%=6 F=Atn(F) Endif If I%=7 F=Log(F) Endif If I%=8 F=Log10(F) Endif If I%=9 F=Exp(F) Endif Erfolg!=True! Endif Endif Next I% If Not Erfolg! Fehler_position%*=Position% Endif Endif Endif ' Endif Faktor=F Return ' ' Procedure N_zeichen ' Repeat Inc Position% If Position%<=Len(Funktion$) Zei$=Mid$(Funktion$,Position%,1) Else Zei$=Zeil_ende$ Endif Until Zei$<>" " Return ' ' ' ----------------------------------------------------------- ' ------------- Ende des Moduls FORMEL.MRG ------------------ ' -----------------------------------------------------------
Bild 6