F A C H H O C H S C H U L E W E D E L
Seminaraufgabe Pascal SS 96
Numerische Lösung von expliziten Differential-Gleichungen erster Ordnung
und grafische Darstellung der Lösungsfunktion
Programm DGL
Udo Becker
PI 6222
13. Januar 1997
Das vorliegende Programm dient zur numerischen Lösung von expliziten Differential-Gleichungen erster Ordnung. Bei einfacheren Differential-Gleichungen bietet eine analytische Lösung zwar genauere Ergebnisse, jedoch lassen sich viele Differential-Gleichungen analytisch nicht lösen. In diesen Fällen kommt nun eine numerische Lösung durch Einschrittverfahren in Betracht. Als numerische Lösung erhält man x-y-Wertepaare in Form einer Wertetabelle, die durch das Programm als Funktion grafisch dargestellt werden.
Durch ein Einschrittverfahren werden aus vorhandenen Funktionswerten nachfolgende Nährungwerte berechnet. Als Voraussetzung für die Berechnung wird also ein Paar von x-y-Werten benötigt, man spricht von einem Anfangswertproblem.
Hierbei ist für die Genauigkeit der Berechnung die Schrittweite von entscheidender Bedeutung. Bei kleinerer Schrittweite werden im Prinzip genauere Werte berechnet, jedoch müssen in einem vorgegebenem Intervall mehr Berechnungen durchgeführt werden, so daß die Rundungsfehler zunehmen. Hieraus ergibt sich die Notwendigkeit einer Schrittweitensteuereung, die in diesem Programm mit den Einbettungsformeln von England nach dem Runge-Kutta-Verfahren durchgeführt wird.
Das Programm wurde in Borland Turbo Pascal 7.01 geschrieben.
Das Hauptprogramm wurde als Turbo Vision Standard Objekt definiert, somit steht dem Benutzer eine für Turbo Vision Programme übliche Umgebung zur Verfügung. Die Bedienung kann mit der Maus oder über Tastatur erfolgen. Beim Start erscheint eine kurze Programminformation.
In der Menüleiste sind die Programmoptionen ‘Eingabe’, ‘Laden’, ‘T-Rechner’ und ‘Info’ sowie eine Uhr untergebracht. Die Statusleiste enthält Informationen über Tastaturbefehle.
Über ‘F10’ läßt sich die Menüleiste aktivieren. Die Programmoptionen könne ebenfalls mit der Tastenkombination ‘Alt+<Markierter Buchstabe>‘ aufgerufen werden. Mit der Escape-Taste lassen sich Fenster schließen.
Beendet wird das Programm mit der Tastenkombinatin ‘Alt+X’ oder mit der Maus durch anklicken von ‘Exit’.
Im Eingabefenster wird der Benutzer aufgefordert, die zu lösende Differential-Gleichung in expliziter Form einzugeben. Diese muß in der im Pascal-Quellcode üblichen Schreibweise vorliegen. Der Ausdruck ‘dy/dx =‘ ist bereits vorgegeben und darf nicht eingegeben werden. Folgende Ausdrücke sind erlaubt:
| x, y | Variable |
| (, ) | Klammern |
| 0..9 | Zahlen |
| +, -, *, / | Grundrechenarten |
| sin, cos, tan, arctan | trigonometrische Funktionenen |
| exp | Exponentionalfunktion |
| ln | natürlicher Logarithmus |
| log | Logarithmus zur Basis 10 |
| sqr | Quadrat |
| sqrt | Quadratwurzel |
| abs | Betrag |
| int | ganzzahliger Anteil |
| frac | nichtganzzahliger Anteil |
Erfolgt die Eingabe der Differential-Gleichung nicht in korrekter Weise wird der Benutzer durch eine Fehlermeldung aufgefordert, die Eingabe zu korrigieren.
Weiterhin müssen im Eingabefenster der x-Minimalwert, der x-Maximalwert, der y-Anfangswert sowie die Genauigkeitsschrake e eingegeben werden. In diesen Eingabefeldern werden nur Dezimalzahlen akzeptiert. Hier erfolgt ebenfalls eine Prüfung, ob korrekte Werte eingegeben wurden, die im negativen Fall eine Fehlermeldung hervorruft.
Das Eingabefenster enthält zwei Funktionsknöpfe: einen Abbruchknopf, der das Eingabefenster schließt, und einen einen Ok-Knopf, der die Berechnung und bei fehlerfreier Rechnung anschließend die Grafische Ausgabe der Funktion veranlaßt.
Fehler während der Berechnung wie z.B. Fließkommaüberläufe oder Divisionen durch Null erzeugen eine Fehlermeldung mit Angabe der entsprechenden x- und y-Werte, so daß der Benutzer den Auswertungsbereich der Funktion entsprechen anpassen kann.
Beim Öffnen des Eingabefensters werden in die Eingabefelder automatisch die Parameter der letzten Berechnung aus der Datei DGL.PAR geladen, ebenfalls werden die Parameter beim schließen des Eingabefensters in dieser Datei gespeichert.
Nach der Berechnung oder nachdem eine bereits vorhandene Datei geladen wurde erfolgt die grafische Ausgabe. Hier wird die Funktion in einem nach den Minimal- und Maximalwerten skalierten Koordinatensystem dargestellt.
Der Grafik-Bildschirm kann mit der Escape-Taste beendet werden.
Wurde eine Funktion berechnet und grafisch dargestellt wird der Benutzer gefragt, ob er die Für eine erneute Darstellung der Funktion benötigten Daten abspeichern möchte.
Für das Abspeichern der Darstellungs-Daten wird ein Turbo Vision Standard Dialog verwendet, der es dem Benutzer erlaubt, die Datei an einer beliebigen Stelle in seinem Dateisystem abzulegen. Für die zu speichernden Dateien sollte die Erweiterung ‘* .DGL’ verwendet werden, die auch vorgegeben wird.
Ist bereits eine Datei mit dem gewähltem Namen vorhanden wird gefragt, ob diese überschrieben werden soll.
Der Lade-Dialog ist ebenfalls ein Turbo Vision Standard Dialog. Der Benutzer kann sein Dateisystem nach Dateien mit der Erweiterung ‘* .DGL’ durchsuchen und diese laden. Wird eine Funktion geladen erfolgt die grafische Ausgabe.
Die Auswahl ‘T-Rechner’ gibt einen einfachen Taschenrechner aus einer Turbo Vision Standard Unit auf den Bildschirm.
Unter ‘Info’ erhält man eine kurze Programminformation.
{-------------------------------------------------------------------------}
{ Programm zur numerischen L”sung von expliziten Differential-Gleichungen
erster Ordnung
Udo Becker 1996/97 }
program DGL;
{$X+}
{$S+}
{$M 65520,8192,655360}
{-------------------------------------------------------------------------}
uses
DGLGlob, Etc, Input, LoadSave,
{ Turbo Pascal Standard Units }
App, Drivers, Gadgets, Memory, Menus, Objects, Views;
type
TDGL = object(TApplication)
Clock : PClockView;
Heap : PHeapView;
constructor Init;
procedure HandleEvent(var Event : TEvent); virtual;
procedure Idle; virtual;
procedure InitMenuBar; virtual;
procedure InitStatusLine; virtual;
end;
const
HeapSize = 48 * (1024 div 16); { 48k Heap }
{-------------------------------------------------------------------------}
{ Initialisierung }
constructor TDGL.Init;
var
R : TRect;
begin
MaxHeapSize := HeapSize;
inherited Init;
GetExtent(R);
R.A.X := R.B.X - 9;
R.B.Y := R.A.Y + 1;
Clock := New(PClockView, Init(R));
Insert(Clock);
GetExtent(R);
Dec(R.B.X);
R.A.X := R.B.X - 9;
R.A.Y := R.B.Y - 1;
Heap := New(PHeapView, Init(R));
Insert(Heap);
Info;
end; { Init }
{-------------------------------------------------------------------------}
{ Auswahl der Handlungsm”glichkeiten }
procedure TDGL.HandleEvent(var Event: TEvent);
begin
inherited HandleEvent(Event);
case Event.What of evCommand:
begin
case Event.Command of
cmEingabe : Eingabe;
cmLaden : Laden;
cmRechner : Rechner;
cmInfo : Info;
else
Exit;
end;
ClearEvent(Event);
end;
end;
end; { HandleEvent }
{-------------------------------------------------------------------------}
{ Uhrzeit und Speicherbelegung aktualisieren }
procedure TDGL.Idle;
begin
inherited Idle;
Clock^.Update;
Heap^.Update;
end; { Idle }
{-------------------------------------------------------------------------}
{ Menleiste }
procedure TDGL.InitMenuBar;
var
R : TRect;
begin
GetExtent(R);
R.B.Y := R.A.Y+1;
MenuBar := New(PMenuBar, Init(R, NewMenu(
NewItem('~E~ingabe', '', kbNoKey, cmEingabe, hcEingabe,
NewItem('~L~aden', '', kbNoKey, cmLaden, hcLaden,
NewItem('~T~-Rechner', '', kbNoKey, cmRechner, hcRechner,
NewItem('~I~nfo', '', kbNoKey, cmInfo, hcInfo,
nil)))))));
end; { InitMenuBar }
{-------------------------------------------------------------------------}
{ Statuszeile }
procedure TDGL.InitStatusLine;
var
R : TRect;
begin
GetExtent(R);
R.A.Y := R.B.Y - 1;
StatusLine := New(PStatusLine, Init(R,
NewStatusDef(0, $FFFF,
NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit,
NewStatusKey('~F10~ Menu', kbF10, cmMenu,
NewStatusKey('~Esc~ Fenster schlieáen', kbEsc, cmClose,
nil))),
nil)));
end; { InitStatusLine }
{-------------------------------------------------------------------------}
var
DG : TDGL;
begin { DGL }
with DG do
begin
Init;
Run;
Done;
end;
end. { DGL }
{-------------------------------------------------------------------------}
{-------------------------------------------------------------------------}
{ Deklarierung globaler Typen, Konstanten, Variablen, Funktionen und
Prozeduren }
unit DGLGlob;
{$D-}
{-------------------------------------------------------------------------}
interface
type
RParameter = record
DGLEingabe : string;
Eingaben : array [0..3] of string [12];
end;
DarstellWerte = record
x, y : word;
end;
const
cmInfo = 1002;
cmRechner = 1006;
cmEingabe = 1007;
cmLaden = 1008;
hcRechner = 4;
hcInfo = 8;
hcEingabe = 21;
hcLaden = 22;
dw_max = 5000;
var
Parameter : RParameter;
DiffGl : string;
x_min, x_max, y_anfang, e : real;
nd : word;
dw : array [0..dw_max] of DarstellWerte;
Skala : array [0..11] of word;
n_xBeschriftung, n_yBeschriftung : byte;
x_Beschriftung, y_Beschriftung : array [0..9] of string;
FormelCode : array [0..1000] of word;
Fehler, FehlerCode : integer;
Ok : boolean;
function Exists(Fn : string) : boolean;
procedure ValueR(Param : string; var a : real);
procedure ValueI(Param : string; var i : integer);
{-------------------------------------------------------------------------}
implementation
{--------------------------------------------------------------------------}
{ Prfung ob eine Datei vorhanden ist }
function Exists(Fn : string) : boolean;
var
Datei : file;
begin
Assign(Datei, Fn);
{$I-}
Reset(Datei);
{$I+}
if IOResult = 0 then
begin
Exists := true;
Close(Datei);
end
else Exists := false;
end; { Exists }
{--------------------------------------------------------------------------}
{ Konvertierung eines String in einen Real-Wert }
procedure ValueR(Param : string; var a : real);
begin
Val(Param, a, Fehler);
Ok := Ok and (Fehler = 0)
end; { ValueR }
{-------------------------------------------------------------------------}
{ Konvertierung eines String in einen Integer-Wert }
procedure ValueI(Param : string; var i : integer);
begin
Val(Param, i, Fehler);
Ok := OK and (Fehler = 0)
end;
{-------------------------------------------------------------------------}
end. { DGLGlob }
{--------------------------------------------------------------------------}
{-------------------------------------------------------------------------}
{ Eingabe-Dialog und Prfung der Eingaben }
unit Input;
{-------------------------------------------------------------------------}
interface
uses
Anzeige, Compil, DGLGlob, LoadSave, Rechnung,
{ Turbo Pascal Standard Units }
App, Dialogs, MsgBox, Objects, Views;
procedure Eingabe;
{-------------------------------------------------------------------------}
implementation
{-------------------------------------------------------------------------}
{ Eingabe-Dialog und Prfung der Eingaben }
procedure Eingabe;
var
R : TRect;
D, DD : PDialog;
Bruce : PView;
Command : word;
Strng : string;
AnzBytes : integer;
begin
{ Laden der Parameter fr das Eingabefenster }
ParFileRead;
repeat
{ Parameter der letzten Rechnung }
Parameter.DGLEingabe := DiffGl;
Str(x_min: 8: 4, Parameter.Eingaben[0]);
Str(x_max: 8: 4, Parameter.Eingaben[1]);
Str(y_anfang: 8: 4, Parameter.Eingaben[2]);
Str(e: 11: 10, Parameter.Eingaben[3]);
{ Eingabefenster }
R.Assign(3, 4, 77, 18);
DD := New(PDialog,Init(R,'Eingabe'));
DD^.HelpCtx := hcEingabe;
with DD^ do
begin
{ Feld fr Differential-Gleichung }
R.Assign(11, 3, 71, 4);
Bruce := New(PInputLine, Init(R, 255));
Insert(Bruce);
Strng := 'dy/dx =';
R.Assign(2, 3, 3+Length(Strng), 4);
Insert(New(PLabel, Init(R, Strng, Bruce)));
Strng := 'Differential-Gleichung:';
R.Assign(26, 2, 27+Length(Strng), 3);
Insert(New(PStaticText, Init(R, Strng)));
{ Felder fr x-Wertebereich }
R.Assign(32, 5, 46, 6);
Bruce := New(PInputLine, Init(R, 12));
Insert(Bruce);
Strng := 'x_min =';
R.Assign(20, 5, 21+Length(Strng), 6);
Insert(New(PLabel, Init(R, Strng, Bruce)));
R.Assign(57, 5, 71, 6);
Bruce := New(PInputLine, Init(R, 12));
Insert(Bruce);
Strng := 'x_max =';
R.Assign(48, 5, 49+Length(Strng), 6);
Insert(New(PLabel, Init(R, Strng, Bruce)));
Strng := 'x-Wertebereich:';
R.Assign(3, 5, 3+Length(Strng), 6);
Insert(New(PStaticText, Init(R, Strng)));
{ Feld fr y-Anfangswert }
R.Assign(32, 7, 46, 8);
Bruce := New(PInputLine, Init(R, 12));
Insert(Bruce);
Strng := 'y(x_min) =';
R.Assign(20, 7, 21+Length(Strng), 8);
Insert(New(PLabel, Init(R, Strng, Bruce)));
Strng := 'y-Anfangswert:';
R.Assign(3, 7, 4+Length(Strng), 8);
Insert(New(PStaticText, Init(R, Strng)));
{ Feld fr Genauigkeit }
R.Assign(32, 9, 46, 10);
Bruce := New(PInputLine, Init(R, 12));
Insert(Bruce);
Strng := 'e =';
R.Assign(20, 9, 21+Length(Strng), 10);
Insert(New(PLabel, Init(R, Strng, Bruce)));
Strng := 'Genauigkeit:';
R.Assign(3, 9, 4+Length(Strng), 10);
Insert(New(PStaticText, Init(R, Strng)));
{ Buttons }
R.Assign(21, 11, 31, 13);
Insert(New(PButton, Init(R, '~B~ild', cmOk, bfDefault)));
R.Assign(43, 11, 53, 13);
Insert(New(PButton, Init(R, '~E~nde', cmCancel, bfNormal)));
{ Parameter einfgen }
SetData(Parameter);
Command := DeskTop^.ExecView(DD);
if Command <> cmCancel then
begin
{ Parameter einlesen }
GetData(Parameter);
Ok := true;
DiffGl := Parameter.DGLEingabe;
ValueR(Parameter.Eingaben[0], x_min);
ValueR(Parameter.Eingaben[1], x_max);
ValueR(Parameter.Eingaben[2], y_anfang);
ValueR(Parameter.Eingaben[3], e);
Ok := Ok and (x_min < x_max);
end
else Ok := false;
if (Command = cmOk) and Ok then
begin
{ Formel-Code erzeugen }
Compile(DiffGl, FormelCode, SizeOf(FormelCode), true, Fehler,
AnzBytes);
if Fehler = 0 then
begin
{ Berechnung der N„hrung und der Darstellungs-Daten }
Berechnung;
if FehlerCode = 0 then
begin
{ Grafik-Ausgabe }
Grafik;
{ Option zum Speichern der Darstellungs-Daten }
R.Assign(0, 0, 45, 9);
D := New(PDialog, Init(R,'Speichern ?'));
with D^ do
begin
Options := Options or ofCentered;
R.Grow(-1, -1);
Dec(R.B.Y, 3);
Insert(New(PStaticText, Init(R, #13+^C'Daten speichern ?')));
R.Assign(9, 6, 19, 8);
Insert(New(PButton, Init(R, '~J~a', cmYes, bfDefault)));
R.Assign(25, 6, 35, 8);
Insert(New(PButton, Init(R, '~N~ein', cmNo, bfNormal)));
end;
Command := Desktop^.ExecView(D);
if (Command = cmYes) then Speichern;
Dispose(D, Done);
end;
end;
end;
if (Command = cmOk) and not Ok then
MessageBox(#3+'Eingabefehler:'+#13+#3+'alle Werte Zahlen ?'+
#13+#3+'x_min < x_max ?', nil, mfError or mfOkButton);
end;
Dispose(DD, Done)
until (Command = cmCancel);
{ Speichern der Parameter aus dem Eingabefenster }
ParFileWrite;
end; { Eingabe }
{-------------------------------------------------------------------------}
end. { Input }
{-------------------------------------------------------------------------}
{-------------------------------------------------------------------------}
{ Berechnung der N„hrung und der Darstellungs-Daten }
unit Rechnung;
{-------------------------------------------------------------------------}
interface
uses
Compil, DGLGlob, Error,
{ Turbo Pascal Standard Units }
MsgBox, Objects;
procedure DarstellBer;
procedure SkalaBer;
procedure Naehrung;
procedure Berechnung;
{-------------------------------------------------------------------------}
implementation
var
x_next, x_last, x_skal, x_minskal, x_maxskal, x_faktor,
y_next, y_last, y_skal, y_minskal, y_maxskal, y_faktor,
y_min, y_max : real;
{-------------------------------------------------------------------------}
{ Berechnung Darstellungs-Daten fr die Funktion mit erneuter Berechnung
der N„hrung }
procedure DarstellBer;
var
i, x_tmp, y_tmp : integer;
h, s, y4, y5, k1, k2, k3, k4, k5, k6 : real;
begin
i := 1;
dw[0].x := round((x_min-x_minskal)*x_faktor)+19;
dw[0].y := -(round((y_anfang-y_minskal)*y_faktor)-419)+19;
x_last := x_min;
y_last := y_anfang;
h := (x_max-x_min)/100;
repeat
repeat
{ n„chster x-Wert }
x_next := x_last + h;
{ K-Werte }
k1 := Rechne(FormelCode, x_last, y_last);
k2 := Rechne(FormelCode, x_last+h/2, y_last+h*k1/2);
k3 := Rechne(FormelCode, x_last+h/2, y_last+h*(k1+k2)/4);
k4 := Rechne(FormelCode, x_last+h, y_last+h*(-k2+2*k3));
k5 := Rechne(FormelCode, x_last+2*h/3, y_last+h*(7*k1+10*k2+k4)/27);
k6 := Rechne(FormelCode, x_last+h/5,
y_last+h*(28*k1-125*k2+546*k3+54*k4-378*k5)/625);
{ N„hrung 4. Ordnung }
y4 := y_last+h*(k1+4*k3+k4)/6;
{ N„hrung 5. Ordnung }
y5 := y_last+h*(14*k1+35*k4+162*k5+125*k6)/336;
{ s-Parameter }
if y4 = y5 then s := 1 else s := sqrt(sqrt(h*e/abs(y4-y5)));
{ Schrittweite h verkleinern }
if s < 1 then if s > 1/2 then h := s*h else h := h/2;
{ Schrittweite h zu klein, endlose Rekursion vermeiden }
if h < (x_max-x_min)/1000000 then h := (x_max-x_min)/1000000;
until (s >= 1) or (h <= (x_max-x_min)/999999);
{ berechneten y-Wert bernehmen }
y_next := y5;
{ Schrittweite h vergrӇern }
if s >= 1 then if s < 2 then h := s*h else h := 2*h;
x_last := x_next;
y_last := y_next;
{ Darstellungs-Daten bestimmen }
x_tmp := round((x_next-x_minskal)*x_faktor)+19;
y_tmp := -(round((y_next-y_minskal)*y_faktor)-419)+19;
if (x_tmp <> dw[i-1].x) or (y_tmp <> dw[i-1].y) then
begin
dw[i].x := x_tmp;
dw[i].y := y_tmp;
inc(i);
end;
until (x_last >= x_max) or (i = dw_max);
nd := i-1;
end; { DarstellBer }
{-------------------------------------------------------------------------}
{ Berechnung der Darstellungs-Daten fr das Koordinaten-System }
procedure SkalaBer;
{-------------------------------------------------------------------------}
{ Berechnung von Zehnerpotenzen aus dem Exponenten }
function Zehnerpotenz(Exponent : integer) : real;
var
i : integer;
Ergebnis : real;
Strng : string;
begin
Strng := '1';
if Exponent > 0 then for i := 1 to Exponent do Strng := Strng+'0';
if Exponent < -1 then for i := -2 downto Exponent do Strng := '0'+Strng;
if Exponent < 0 then Strng := '0.'+Strng;
ValueR(Strng, Ergebnis);
Zehnerpotenz := Ergebnis;
end; { Zehnerpotenz }
{-------------------------------------------------------------------------}
var
i, sig, exp : integer;
skalmitte, tmpR : real;
tmpS : string [24];
abschneiden : boolean;
begin { SkalBer }
{ x-Skalenweite }
tmpR := (x_max-x_min)/8;
str(tmpR, tmpS);
ValueI(copy(tmpS, 2, 1), sig);
ValueI(copy(tmpS, 19, 5), exp);
case sig of
0 : x_skal := 1;
1 : x_skal := 2;
2..4 : x_skal := 5;
5..9 : x_skal := 10;
end;
x_skal := x_skal*(Zehnerpotenz(exp));
{ Mitte der x-Skala }
skalmitte := (x_min+x_max)/2;
if skalmitte >= 0 then
begin
tmpR := -x_skal;
repeat
tmpR := tmpR+x_skal;
until skalmitte-tmpR <= 0;
skalmitte := tmpR;
end
else
begin
tmpR := x_skal;
repeat
tmpR := tmpR-x_skal;
until skalmitte-tmpR >= 0;
skalmitte := tmpR;
end;
{ x-Minimal- und -Maximal-Skalenwert }
x_minskal := skalmitte;
repeat
x_minskal := x_minskal-x_skal;
until x_minskal < x_min+0.1*x_skal;
x_maxskal := skalmitte;
repeat
x_maxskal := x_maxskal+x_skal;
until x_maxskal > x_max-0.1*x_skal;
{ x-Skalenbeschriftung }
i := 0;
tmpR := x_minskal;
repeat
tmpR := tmpR+x_skal;
if abs(tmpR) > 0.5*x_skal then
begin
Str(tmpR, tmpS);
if exp < 0 then
begin
if copy(tmpS, 4-exp, 1) = '9' then
begin
tmpR := tmpR+0.1*Zehnerpotenz(exp);
Str(tmpR, tmpS);
end;
x_Beschriftung[i] :=
copy(tmpS, 1, 3-exp)+copy(tmpS, 18, 2)+copy(tmpS, 22, 2);
end
else x_Beschriftung[i] :=
copy(tmpS, 1, 4)+copy(tmpS, 18, 2)+copy(tmpS, 22, 2);
end
else
begin
tmpR := 0;
x_Beschriftung[i] := '';
end;
inc(i);
until tmpR >= x_maxskal-0.5*x_skal;
n_xBeschriftung := i-1;
{ nichtsignifikante x-Stellen abschneiden }
repeat
abschneiden := false;
if length(x_Beschriftung[i]) > 8 then
begin
i := -1;
repeat
abschneiden := false;
inc(i);
if copy(x_Beschriftung[i], length(x_Beschriftung[i])-4, 1) = '0'
then abschneiden := true;
until (abschneiden = false) or (i = n_xBeschriftung);
abschneiden := false;
if i = n_xBeschriftung then
begin
abschneiden := true;
for i := 0 to n_xBeschriftung do x_Beschriftung[i] :=
copy(x_Beschriftung[i], 1, length(x_Beschriftung[i])-5)+
copy(x_Beschriftung[i], length(x_Beschriftung[i])-3, 4);
end;
end;
until (abschneiden = false);
{ y-Skalenweite }
tmpR := (y_max-y_min)/8;
str(tmpR, tmpS);
ValueI(copy(tmpS, 2, 1), sig);
ValueI(copy(tmpS, 19, 5), exp);
case sig of
0 : y_skal := 1;
1 : y_skal := 2;
2..4 : y_skal := 5;
5..9 : y_skal := 10;
end;
y_skal := y_skal*(Zehnerpotenz(exp));
{ Mitte der y-Skala }
skalmitte := (y_min+y_max)/2;
if skalmitte >= 0 then
begin
tmpR := -y_skal;
repeat
tmpR := tmpR+y_skal;
until skalmitte-tmpR <= 0;
skalmitte := tmpR;
end
else
begin
tmpR := y_skal;
repeat
tmpR := tmpR-y_skal;
until skalmitte-tmpR >= 0;
skalmitte := tmpR;
end;
{ y-Minimal- und -Maximal-Skalenwert }
y_minskal := skalmitte;
repeat
y_minskal := y_minskal-y_skal;
until y_minskal < y_min+0.1*y_skal;
y_maxskal := skalmitte;
repeat
y_maxskal := y_maxskal+y_skal;
until y_maxskal > y_max-0.1*y_skal;
{ y-Skalenbeschriftung }
i := 0;
tmpR := y_minskal;
repeat
tmpR := tmpR+y_skal;
if abs(tmpR) > 0.5*y_skal then
begin
Str(tmpR, tmpS);
if exp < 0 then
begin
if copy(tmpS, 4-exp, 1) = '9' then
begin
tmpR := tmpR+0.1*Zehnerpotenz(exp);
Str(tmpR, tmpS);
end;
y_Beschriftung[i] :=
copy(tmpS, 1, 3-exp)+copy(tmpS, 18, 2)+copy(tmpS, 22, 2);
end
else y_Beschriftung[i] :=
copy(tmpS, 1, 4)+copy(tmpS, 18, 2)+copy(tmpS, 22, 2);
end
else
begin
tmpR := 0;
y_Beschriftung[i] := '';
end;
inc(i);
until tmpR >= y_maxskal-0.5*y_skal;
n_yBeschriftung := i-1;
{ nichtsignifikante y-Stellen abschneiden }
repeat
abschneiden := false;
if length(y_Beschriftung[i]) > 8 then
begin
i := -1;
repeat
abschneiden := false;
inc(i);
if copy(y_Beschriftung[i], length(y_Beschriftung[i])-4, 1) = '0'
then abschneiden := true;
until (abschneiden = false) or (i = n_yBeschriftung);
abschneiden := false;
if i = n_yBeschriftung then
begin
abschneiden := true;
for i := 0 to n_yBeschriftung do y_Beschriftung[i] :=
copy(y_Beschriftung[i], 1, length(y_Beschriftung[i])-5)+
copy(y_Beschriftung[i], length(y_Beschriftung[i])-3, 4);
end;
end;
until (abschneiden = false);
{ Umrechnungsfaktoren fr Bildschirmdarstellung }
x_faktor := 600/(x_maxskal-x_minskal);
y_faktor := 420/(y_maxskal-y_minskal);
{ x-Achse }
if x_minskal < 0.5*x_skal then Skala[0] := 19 else Skala[0] := 39;
if y_minskal > -0.5*y_skal then Skala[1] := 439
else if y_maxskal < 0.5*y_skal then Skala[1] := 19
else Skala[1] := -(round((-y_minskal)*y_faktor)-419)+19;
if x_maxskal > -0.5*x_skal then Skala[2] := 619 else Skala[2] := 599;
{ y-Achse }
if x_minskal > -0.5*x_skal then Skala[3] := 19
else if x_maxskal < 0.5*x_skal then Skala[3] := 619
else Skala[3] := round((-x_minskal)*x_faktor)+19;
if y_maxskal > -0.5*y_skal then Skala[4] := 19 else Skala[4] := 39;
if y_minskal < 0.5*y_skal then Skala[5] := 439 else Skala[5] := 419;
{ Skalierungsfaktoren }
Skala[6] := round(x_skal*x_faktor);
Skala[7] := round(y_skal*y_faktor);
end; { SlalaBer }
{-------------------------------------------------------------------------}
{ Berechnung der N„hrung }
procedure Naehrung;
var
h, s, y4, y5, k1, k2, k3, k4, k5, k6 : real;
begin
y_min := y_anfang;
y_max := y_anfang;
x_last := x_min;
y_last := y_anfang;
h := (x_max-x_min)/100;
repeat
repeat
{ n„chster x-Wert }
x_next := x_last + h;
{ K-Werte }
k1 := Rechne(FormelCode, x_last, y_last);
k2 := Rechne(FormelCode, x_last+h/2, y_last+h*k1/2);
k3 := Rechne(FormelCode, x_last+h/2, y_last+h*(k1+k2)/4);
k4 := Rechne(FormelCode, x_last+h, y_last+h*(-k2+2*k3));
k5 := Rechne(FormelCode, x_last+2*h/3, y_last+h*(7*k1+10*k2+k4)/27);
k6 := Rechne(FormelCode, x_last+h/5,
y_last+h*(28*k1-125*k2+546*k3+54*k4-378*k5)/625);
{ N„hrung 4. Ordnung }
y4 := y_last+h*(k1+4*k3+k4)/6;
{ N„hrung 5. Ordnung }
y5 := y_last+h*(14*k1+35*k4+162*k5+125*k6)/336;
{ s-Parameter }
if y4 = y5 then s := 1 else s := sqrt(sqrt(h*e/abs(y4-y5)));
{ Schrittweite h verkleinern }
if s < 1 then if s > 1/2 then h := s*h else h := h/2;
{ Schrittweite h zu klein, endlose Rekursion vermeiden }
if h < (x_max-x_min)/1000000 then h := (x_max-x_min)/1000000;
until (s >= 1) or (h <= (x_max-x_min)/999999);
{ berechneten y-Wert bernehmen }
y_next := y5;
{ Schrittweite h vergrӇern }
if s >= 1 then if s < 2 then h := s*h else h := 2*h;
{ y-Grenzen }
if y_next < y_min then y_min := y_next;
if y_next > y_max then y_max := y_next;
x_last := x_next;
y_last := y_next;
until x_last >= x_max;
end; { Naehrung }
{-------------------------------------------------------------------------}
{ Prfung ob Rechnung durchgefhrt werden kann und Start der Rechnung }
procedure Berechnung;
var
Strng, Strng1, Strng2 : string;
begin
FehlerCode := SetExit(CpuPointer);
case FehlerCode of
0 : begin
Naehrung;
SkalaBer;
DarstellBer;
end;
200 : Strng := 'Division durch 0';
205 : Strng := 'Flieákommaberlauf';
206 : Strng := 'Flieákommazahl zu klein';
207 : Strng := 'Unzul„ssige Werte'
else Strng := 'Rechenfehler unbekannter Art'
end;
if FehlerCode <> 0 then
begin
Str(x_last: 8: 3, Strng1);
Strng1 := 'x = ' + Strng1;
Str(y_last: 8: 3, Strng2);
Strng2 := 'y = ' + Strng2;
MessageBox(#3+Strng+#13+#3+Strng1+#13+#3+Strng2, nil,
mfError or mfOKButton);
end;
end; { Berechnung }
{-------------------------------------------------------------------------}
end. { Rechnung }
{-------------------------------------------------------------------------}
{-------------------------------------------------------------------------}
{ Erzeugung des Formel-Codes aus der Differential-Gleichung und Berechnung
der K-Werte mit dem Formel-Code }
unit Compil;
{-------------------------------------------------------------------------}
interface
uses
DGLGlob, Error,
{ Turbo Pascal Standard Units }
MsgBox, Objects, Views;
function Rechne(var Code; x, y : real): real;
procedure Compile(var Ausdruck; var Code; Size : integer;
Meldung : boolean; var ErrPos, Pc : integer);
{-------------------------------------------------------------------------}
implementation
var
CpuSave : ExitBuf;
{-------------------------------------------------------------------------}
{ Berechnung der K-Werte mit dem Formel-Code }
function Rechne(var Code; x, y : real) : real;
const
MaxStack = 50;
var
Pc, Sp : integer;
Oc : byte;
Stack : array [0..MaxStack] of real;
OpCode : array [0..MaxInt] of byte absolute Code;
begin
Pc := 0;
Sp := 0;
repeat
Oc := OpCode[Pc];
Inc(Pc);
case Oc of
0 : begin
Inc(Sp);
Stack[Sp] := x;
end;
1 : begin
Inc(Sp);
Stack[Sp] := y;
end;
2 : begin
Inc(Sp);
Move(OpCode[Pc], Stack[Sp], SizeOf(real));
Inc(Pc, SizeOf(real));
end;
3 : begin
Dec(Sp);
Stack[Sp] := Stack[Sp]+Stack[Succ(Sp)];
end;
4 : begin
Dec(Sp);
Stack[Sp] := Stack[Sp]-Stack[Succ(Sp)];
end;
5 : begin
Dec(Sp);
Stack[Sp] := Stack[Sp]*Stack[Succ(Sp)];
end;
6 : begin
Dec(Sp);
Stack[Sp] := Stack[Sp]/Stack[Succ(Sp)];
end;
7 : Stack[Sp] := Sin(Stack[Sp]);
8 : Stack[Sp] := Cos(Stack[Sp]);
9 : Stack[Sp] := Sin(Stack[Sp])/Cos(Stack[Sp]);
10 : Stack[Sp] := ArcTan(Stack[Sp]);
11 : Stack[Sp] := Exp(Stack[Sp]);
12 : Stack[Sp] := Ln(Stack[Sp]);
13 : Stack[Sp] := Ln(Stack[Sp])/Ln(10.0);
14 : Stack[Sp] := Sqr(Stack[Sp]);
15 : Stack[Sp] := Sqrt(Stack[Sp]);
16 : Stack[Sp] := Frac(Stack[Sp]);
17 : Stack[Sp] := Int(Stack[Sp]);
18 : Stack[Sp] := Abs(Stack[Sp]);
19 : Stack[Sp] := -Stack[Sp];
end;
until Oc >= 20;
Rechne := Stack[1];
end; { Rechne }
{-------------------------------------------------------------------------}
{ Erzeugung des Formel-Codes aus der Differential-Gleichung }
procedure Compile(var Ausdruck; var Code; Size : integer;
Meldung : boolean; var ErrPos, Pc : integer);
type
RunTime = (LoadVarX, LoadVarY, Push, Add, Sub, Mult, Divi, Sin, Cos,
Tan, ArcTan, Exp, Ln, Log, Sqr, Sqrt, Frac, Int, Abs, Neg, Stop);
Str1 = string [1];
const
FNam : array [Sin..Abs] of string [6] = ('SIN', 'COS', 'TAN', 'ARCTAN',
'EXP', 'LN', 'LOG', 'SQR', 'SQRT', 'FRAC', 'INT', 'ABS');
var
Formel : string [255] absolute Ausdruck;
OpCode : array [0..MaxInt] of Runtime absolute Code;
Chp, Tiefe : integer;
K, Dummy : word;
Ch : char;
{-------------------------------------------------------------------------}
procedure Fehler(Nr : integer);
var
i, j : integer;
R : TRect;
Strng, Strng1 : string;
begin
if Meldung then
begin
case Nr of
0 : Strng1 := 'Speicherplatz im Codefeld reicht nicht';
1 : Strng1 := 'Operator erwartet';
2 : Strng1 := '"(" erwartet';
3 : Strng1 := 'Unbekannte Funktion';
4 : Strng1 := '")" erwartet';
5 : Strng1 := 'Konstante, Variable oder Funktion erwartet';
6 : Strng1 := 'Fehler in Konstante';
7 : Strng1 := 'Klammer-Fehler'
end;
Strng := '';
for i := 1 to Chp-1 do Strng := Strng + ' ';
Strng := Strng + '^';
j := Length(Strng);
for i := j+1 TO Length(Formel) do Strng := Strng + ' '
end;
if ErrPos = 0 then ErrPos := Chp;
R.Assign(13, 6, 67, 17);
MessageBoxRect(R, #3+Formel+#13+#3+Strng+#13+#13+#3+Strng1, nil,
mfError or mfOKButton);
LongExit(CpuSave, Dummy);
end; { Fehler }
{-------------------------------------------------------------------------}
procedure GetChar;
begin
repeat
Inc(Chp);
if Chp > Length(Formel) then Ch := #0 else Ch := Upcase(Formel[Chp]);
until Ch <> ' '
end; { GetChar }
{-------------------------------------------------------------------------}
procedure PutCode(B : Runtime);
begin
if Pc >= Size then Fehler(0) else OpCode[Pc] := B;
Inc(Pc)
end; { PutCode }
{-------------------------------------------------------------------------}
procedure PutReal(R : real);
begin
if Pc + SizeOf(real) >= Size then Fehler(0)
else Move(R, Opcode[Pc], SizeOf(real));
Inc(Pc,SizeOf(real))
end; { PutReal }
{-------------------------------------------------------------------------}
procedure AddSub; Forward;
{-------------------------------------------------------------------------}
procedure Konstante (var Vorz : Str1);
var
Fp : real;
Err1, Err2 : integer;
begin
Val(Copy(Formel, Chp, 255)+'?', Fp, Err1);
Val(Vorz+Copy(Formel, Chp, pred(err1)), fp, Err2);
if Err2 <> 0 then Fehler(6);
PutCode(Push);
PutReal(Fp);
Chp := Chp + Err1 - 2;
GetChar;
if not (Ch in ['-','+','/','*',')',#0]) then Fehler(1)
end; { Konstante }
{-------------------------------------------------------------------------}
procedure Term;
var
Name : string [6];
i, S : Runtime;
Vorz : Str1;
begin
GetChar;
if Ch in [#0,')'] then
begin
Fehler(5);
Exit
end;
if Ch = '-' then
begin
Vorz := '-';
GetChar
end
else Vorz := '';
if Ch = '(' then
begin
Inc(Tiefe);
AddSub;
Dec(Tiefe);
if Ch <> ')' then
begin
Fehler(4);
Exit
end;
GetChar
end
else
if Ch in ['0'..'9'] then Konstante(Vorz)
else
begin
Name := '';
while Ch in ['A'..'Z'] do
begin
Name := Name + Ch;
GetChar
end;
if Name = 'X' then PutCode(LoadVarX);
if Name = 'Y' then PutCode(LoadVarY);
if (Name <> 'X') and (Name <> 'Y') then
begin
S := LoadVarX;
for i := Sin to Abs do if Name = FNam[i] then S := I;
S := LoadVarY;
for i := Sin to Abs do if Name = FNam[i] then S := I;
if (S <> LoadVarX) or (S <> LoadVarY) then
begin
if Ch <> '(' then Fehler(2);
Dec(Chp);
Term;
PutCode(S);
end
else Fehler(3);
end;
if Vorz = '-' then PutCode(Neg)
end;
end; { Term }
{-------------------------------------------------------------------------}
procedure MultDiv;
begin
repeat
case Ch of
'*' : begin
Term;
PutCode(Mult)
end;
'/' : begin
Term;
PutCode(Divi)
end;
end;
until not (Ch in ['*', '/']);
end; { MultDiv }
{-------------------------------------------------------------------------}
procedure AddSub;
begin
Term;
if ErrPos = 0 then
repeat
case Ch of
'-' : begin
Term;
MultDiv;
PutCode(Sub)
end;
'+' : begin
Term;
MultDiv;
PutCode(Add)
end;
'(' : Fehler(1);
')' : begin
if Tiefe = 0 then Fehler(7);
Exit;
end;
'*', '/' : MultDiv;
#0 :
else Fehler(1);
end;
until (Ch = #0) or (ErrPos <> 0);
end; { AddSub }
{-------------------------------------------------------------------------}
begin { Compile }
K := SetExit(CpuSave);
if K = 0 then
begin
Chp := 0;
Pc := 0;
ErrPos := 0;
Tiefe := 0;
AddSub;
PutCode(Stop)
end;
end; { Compile }
{-------------------------------------------------------------------------}
end. { Compil }
{-------------------------------------------------------------------------}
{-------------------------------------------------------------------------}
{ Initialisierung des Grafik-Bildschirmes und Ausgabe der Grafik }
unit Anzeige;
{-------------------------------------------------------------------------}
interface
uses
DGLGlob,
{ Turbo Pascal Standard Units }
Crt, Dos, Graph, GraphApp, MsgBox, Objects;
procedure Grafik;
{-------------------------------------------------------------------------}
implementation
{-------------------------------------------------------------------------}
{ Initialisierung des Grafik-Bildschirmes }
procedure Grafik;
{-------------------------------------------------------------------------}
{ Ausgabe der Grafik }
procedure GrafikAnzeige;
var
i, j : integer;
Strng : string;
begin
{ feste Elemente einfgen }
Rectangle(0, 0, GetMaxX, GetMaxY);
Line(0, 459, GetMaxX, 459);
Line(485, 459, 485, GetMaxY);
Strng := 'Weiter mit ';
OutTextXY(500, 466, Strng);
{ Differential-Gleichung ausgeben }
Strng := 'dy/dx = '+DiffGl;
OutTextXY(15, 466, Strng);
{ Koordinatenkreuz zeichnen }
Line(Skala[0], Skala[1], Skala[2], Skala[1]);
OutTextXY(Skala[2]-20, Skala[1]-10, 'x');
Line(Skala[3], Skala[4], Skala[3], Skala[5]);
OutTextXY(Skala[3]-10, Skala[4]+10, 'y');
{ Skalenstriche zeichnen und Skalenbeschriftung }
i := 19+Skala[6];
j := 0;
repeat
if abs(Skala[3]-i) < 10 then i := Skala[3];
Line(i, Skala[1]-3, i, Skala[1]+3);
OutTextXY(i-30, Skala[1]+8, x_Beschriftung[j]);
i := i+Skala[6];
inc(j);
until i > 604;
i := 439-Skala[7];
j := 0;
repeat
if abs(Skala[1]-i) < 10 then i := Skala[1];
Line(Skala[3]-3, i, Skala[3]+3, i);
if Skala[3] < 559 then
OutTextXY(Skala[3]+8, i-3, y_Beschriftung[j])
else OutTextXY(Skala[3]-10*length(y_Beschriftung[j])+10, i-3,
y_Beschriftung[j]);
i := i-Skala[7];
inc(j);
until i < 34;
{ Hilfspunkte zeichnen }
i := 19;
repeat
if abs(Skala[3]-i) < 10 then i := Skala[3];
j := 439;
repeat
if abs(Skala[1]-j) < 10 then j := Skala[1];
PutPixel(i, j, white);
PutPixel(619, j, white);
j := j-Skala[7];
until j < 34;
PutPixel(i, 19, white);
i := i+Skala[6];
until i > 604;
PutPixel(619, 19, white);
{ Funktion zeichnen }
for i := 0 to nd do PutPixel(dw[i].x, dw[i].y, yellow);
end; { GrafikAnzeige }
{-------------------------------------------------------------------------}
var
BGIPath : PString;
GraphOk : boolean;
Taste : char;
begin { Grafik }
BGIPath := NewStr(FExpand('.'));
GraphOk := GraphAppInit(0, 0, BGIPath, true);
if not GraphOk then
MessageBox(#3+'Kann Grafiktreiber nicht finden', nil,
mfOKButton or mfError);
if GraphicsStart then
begin
GrafikAnzeige;
repeat
Taste := readkey
until Taste in [chr(27)]; { Escape-Taste }
GraphicsStop;
end;
end; { Grafik }
{-------------------------------------------------------------------------}
end. { Anzeige }
{-------------------------------------------------------------------------}
{-------------------------------------------------------------------------}
{ Laden und Speichern von Dateien }
unit LoadSave;
{-------------------------------------------------------------------------}
interface
uses
Anzeige, DGLGlob,
{ Turbo Pascal Standard Units }
App, Dialogs, MsgBox, Objects, StdDlg, Views;
procedure ParFileRead;
procedure ParFileWrite;
procedure Laden;
procedure Speichern;
{-------------------------------------------------------------------------}
implementation
const
ParFileName : string = 'DGL.PAR';
Extens : string = '*.DGL';
var
ParamFile, DatFile : text;
FileName : string;
{-------------------------------------------------------------------------}
{ Laden der Parameter fr das Eingabefenster }
procedure ParFileRead;
begin
if Exists(ParFileName) then
begin
Assign(ParamFile, ParFileName);
Reset(ParamFile);
ReadLn(ParamFile, DiffGl);
ReadLn(ParamFile, x_min);
ReadLn(ParamFile, x_max);
ReadLn(ParamFile, y_anfang);
ReadLn(ParamFile, e);
Close(ParamFile)
end
else
begin
DiffGl := 'cos(x)*y';
x_min := -8;
x_max := 0;
y_anfang := exp(sin(-8));
e := 0.000000001;
end;
end; { ParFileRead }
{-------------------------------------------------------------------------}
{ Speichern der Parameter aus dem Eingabefenster }
procedure ParFileWrite;
begin
Assign(ParamFile, ParFileName);
ReWrite(ParamFile);
WriteLn(ParamFile, DiffGl);
WriteLn(ParamFile, x_min);
WriteLn(ParamFile, x_max);
WriteLn(ParamFile, y_anfang);
WriteLn(ParamFile, e);
Close(ParamFile);
end; { ParFileWrite }
{-------------------------------------------------------------------------}
{ ™ffnen einer Darstellungs-Datei }
procedure Laden;
{-------------------------------------------------------------------------}
{ Laden der Daten einer Dartellungs_Datei }
procedure DatFileRead;
var
i : word;
begin
Assign(DatFile, FileName);
Reset(DatFile);
ReadLn(DatFile, DiffGl);
for i := 0 to 7 do ReadLn(DatFile, Skala[i]);
ReadLn(Datfile, n_xBeschriftung);
for i := 0 to n_xBeschriftung do ReadLn(Datfile, x_Beschriftung[i]);
ReadLn(Datfile, n_yBeschriftung);
for i := 0 to n_yBeschriftung do ReadLn(Datfile, y_Beschriftung[i]);
ReadLn(DatFile, nd);
for i := 0 to nd do
begin
ReadLn(DatFile, dw[i].x);
ReadLn(DatFile, dw[i].y);
end;
Close(DatFile);
end; { DatFileRead }
{-------------------------------------------------------------------------}
var
R : TRect;
D : PFileDialog;
Command : word;
begin { Laden }
repeat
D := New(PFileDialog, Init(Extens, 'Datei ”ffnen', '~N~ame',
fdOpenButton, fdReplaceButton));
Command := Desktop^.ExecView(D);
if (Command <> cmCancel) then
begin
D^.GetFileName(FileName);
if Exists(FileName) then
begin
DatFileRead;
Grafik;
end
else MessageBox(#3+'Datei nicht gefunden'+#13+#13, nil,
mfError or mfOKButton);
end;
Dispose(D, Done);
until (Command = cmCancel);
end; { Laden }
{-------------------------------------------------------------------------}
{ Abspeichern einer Darstellungs-Datei }
procedure Speichern;
{-------------------------------------------------------------------------}
{ Speichern der Daten einer Darstellungs-Datei }
procedure DatFileWrite;
var
i : word;
begin
Assign(DatFile, FileName);
ReWrite(DatFile);
WriteLn(DatFile, DiffGl);
for i := 0 to 7 do WriteLn(DatFile, Skala[i]);
WriteLn(Datfile, n_xBeschriftung);
for i := 0 to n_xBeschriftung do WriteLn(Datfile, x_Beschriftung[i]);
WriteLn(Datfile, n_yBeschriftung);
for i := 0 to n_yBeschriftung do WriteLn(Datfile, y_Beschriftung[i]);
WriteLn(DatFile, nd);
for i := 0 to nd do
begin
WriteLn(DatFile, dw[i].x);
WriteLn(DatFile, dw[i].y);
end;
Close(DatFile);
end; { DatFileWrite }
{-------------------------------------------------------------------------}
var
R : TRect;
D : PFileDialog;
begin { Speichern }
Ok := false;
repeat
D := New(PFileDialog, Init(Extens, 'Datei speichern', '~N~ame',
fdOkButton, fdReplaceButton));
if Desktop^.ExecView(D) <> cmCancel then
begin
D^.GetFileName(FileName);
if Exists(FileName) then
begin
if MessageBox(#3+'Datei existiert!'+#13+#3+'šberschreiben?',
nil, mfInformation or mfOkCancel) = cmOk then
begin
Assign(DatFile, FileName);
Erase(DatFile);
DatFileWrite;
Ok := true;
end;
end
else DatFileWrite;
Ok := true
end
else Ok:= true;
Dispose(D, Done);
until Ok = true;
end; { Speichern }
{-------------------------------------------------------------------------}
end. { LoadSave }
{-------------------------------------------------------------------------}
{-------------------------------------------------------------------------}
{ Abfangen von Fehlern in der Berechnung }
unit Error;
{$F+}
{-------------------------------------------------------------------------}
interface
type
ExitBuf = record
Bp, Cs, Ip : word
end;
var
CpuPointer : ExitBuf;
ErrCode : word;
function SetExit(var CpuSave : ExitBuf) : word;
procedure LongExit(var CpuSave : ExitBuf; RetV : word);
{-------------------------------------------------------------------------}
implementation
var
Stack : record
case boolean of
true : (Offset, Segment : word);
false : (Zeiger : ^word)
end;
ExitSave : pointer;
{-------------------------------------------------------------------------}
function SetExit(var CpuSave : ExitBuf) : word;
begin
with Stack do
begin
Zeiger := Ptr(SSeg, SPtr+2);
CpuSave.bp := Zeiger^;
Inc(Offset, 2);
CpuSave.ip := Zeiger^;
Inc(Offset, 2);
CpuSave.cs := Zeiger^
end;
SetExit := 0
end; { SetExit }
{-------------------------------------------------------------------------}
procedure LongExit(var CpuSave : ExitBuf; RetV : word);
var
Dummy : word;
begin
with Stack do
begin
Zeiger := Ptr(SSeg, SPtr+2);
Zeiger^ := CpuSave.bp;
Inc(Offset, 2);
Zeiger^ := CpuSave.ip;
Inc(Offset, 2);
Zeiger^ := CpuSave.cs;
end;
Dummy := RetV
end; { LongExit }
{-------------------------------------------------------------------------}
procedure MyExit;
begin
ExitProc := ExitSave;
if ExitCode in [200, 205, 206, 207] then
begin
ErrCode := ExitCode;
ExitCode := 0;
ErrorAddr := nil;
ExitProc := @MyExit;
LongExit(CpuPointer, ErrCode)
end;
end; { MyExit }
{-------------------------------------------------------------------------}
begin
ExitSave := ExitProc;
ExitProc := @MyExit
end. { Error }
{-------------------------------------------------------------------------}
{-------------------------------------------------------------------------}
{ zus„tzlichen Programmteile }
unit Etc;
{-------------------------------------------------------------------------}
interface
uses
DGLGlob,
{ Turbo Pascal Standard Units }
App, Dialogs, Calc, Objects, Views;
procedure Rechner;
procedure Info;
{-------------------------------------------------------------------------}
implementation
{-------------------------------------------------------------------------}
{ einfacher Taschenrechner aus Turbo Pascal Standard Unit }
procedure Rechner;
var
P : PCalculator;
begin
P := New(PCalculator, Init);
P^.HelpCtx := hcRechner;
Desktop^.Insert(P);
end; { Rechner }
{-------------------------------------------------------------------------}
{ Programm-Information }
procedure Info;
var
D : PDialog;
R : TRect;
begin
R.Assign(0, 0, 45, 11);
D := New(PDialog, Init(R,'Info'));
with D^ do
begin
Options := Options or ofCentered;
R.Grow(-1, -1);
Dec(R.B.Y, 3);
Insert(New(PStaticText, Init(R,
#13+^C'Numerische L”sung von expliziten'#13+
^C'Differential-Gleichungen erster Ordnung'#13+
#13+^C'1996/97'#13+^C'Udo Becker')));
R.Assign(17, 8, 27, 10);
Insert(New(PButton, Init(R, '~O~K', cmOk, bfDefault)));
end;
Desktop^.ExecView(D);
Dispose(D, Done);
end; { Info }
{-------------------------------------------------------------------------}
end. { Etc }
{-------------------------------------------------------------------------}
Auf der Programmdiskette befinden sich folgende Dateien:
Hauptverzeichnis \:
| DGL.EXE | Programm DGL |
| DGL.PAR | Parameter-Datei |
| EGAVGA.BGI | Borland Graphic Interface |
| BEISP1.DGL | Beispieldatei |
| BEISP2A.DGL | Beispieldatei |
| BEISP2B.DGL | Beispieldatei |
| BEISP2C.DGL | Beispieldatei |
Unterverzeichnis \SOURCE:
| DGL.PAS | Hauptprogramm |
| DGLGLOB.PAS | Globale Deklarationen |
| INPUT.PAS | Eingaberoutine |
| RECHNUNG.PAS | Berechnungen |
| COMPIL.PAS | Berechnungshilfen |
| ANZEIGE.PAS | Grafische Ausgabe |
| LOADSAVE.PAS | Laden und Speichern |
| ERROR.PAS | Fehlerbehandlung |
| ETC.PAS | zusätzliche Programmteile |
13. August 2000, Udo Becker