Mathematische Formeln/Funktionen implementieren
-
Hallo,
ich muss ein numerisches Verfahren zum Lösen von DGL´s schreiben (Runge-Kutta wird´s wohl werden...), dabei bin ich auf folgendes Problem gestoßen:
Ich kann ja ohne weiteres eine mathematische Formel so darstellen
double f(const double x) { return pow(x,2) + 2*x - cos (x) }
Wenn nun mein Löser für die eine DGL die Funktion y=f(x) benötigt, übergebe ich diese dann am besten mittels Funktionszeiger oder was würdet ihr vorschlagen? Es muss etwa wie folgt aussehen:
//Pseudocode void loese_dgl(Funktion, Schrittweite, Startwert)
Eine Frage, die sich daran anschließt ist: Wie kann man am einfachsten mathematische Formeln einlesen? Wenn jemand einen Ausdruck wie sin(x)*cos(x) über die Kommandozeile eingibt, habe ich ja erstmal nur einen String und das umwandeln in eine mathematische Funktion stelle ich mir beliebig kompliziert vor, wenn es sich um größere Funktionen mit Beachtung von Punkt vor Strichrechnung handelt etc....
Danke.
-
template<class Func, class SizeType>
void loese_dgl(Func func, SizeType step, SizeType start)
-
KeineAhnung78 schrieb:
Wenn nun mein Löser für die eine DGL die Funktion y=f(x) benötigt, übergebe ich diese dann am besten mittels Funktionszeiger oder was würdet ihr vorschlagen? Es muss etwa wie folgt aussehen:
//Pseudocode void loese_dgl(Funktion, Schrittweite, Startwert)
Mit Funktionszeigern ist es möglich. Besser und flexibler wäre es aber mit sogenannten Funktoren und Templates zu arbeiten. In Deinem Fall also:
template< typename F > void loese_dgl( F funktor, double dt, double t0 );
Diese Lösung schließt Funktionen mit ein; d.h. Du kannst eine Funktion double f( double ) auch übergeben
loese_dgl( f, 0.01, 0.0 );
innerhalb des Templates benutzt Du die Variable 'funktor' wie eine ganz normale Funktion. Also z.B.:
template< typename F > void loese_dgl( F funktor, double dt, double t0 ) { ... dy = funktor( y ); // Ableitung dy ist Funktion des Zustandes y }
KeineAhnung78 schrieb:
Eine Frage, die sich daran anschließt ist: Wie kann man am einfachsten mathematische Formeln einlesen? Wenn jemand einen Ausdruck wie sin(x)*cos(x) über die Kommandozeile eingibt, habe ich ja erstmal nur einen String und das umwandeln in eine mathematische Funktion stelle ich mir beliebig kompliziert vor, wenn es sich um größere Funktionen mit Beachtung von Punkt vor Strichrechnung handelt etc....
es ist nicht trivial. Wenn Du 'keine Ahnung von C++' hast, wird es sehr schwierig.
Noch 'ne Bemerkung zu Deiner Funktion
KeineAhnung78 schrieb:
double f(const double x) { return pow(x,2) + 2*x - cos (x) }
Die Funktion 'pow(x,y)' benutzt ein numerisches Verfahren, da sie für nicht ganzzahlige 'y' konzipiert ist. Ersetze 'pow(x,2)' besser durch 'x*x'.
Gruß
Werner
-
Danke, Funktoren sagen mir ´was. Kenne ich aus der STL. Wäre aber in diesem Zusammenhang trotzdem nicht direkt darauf gekommen
.
-
Da habe ich noch eine Frage zu:
Ich hab´s ausprobiert und einen schönen Runge-Kutta geschrieben. Kein Problem.
Jetzt möchte ich das ganze in mein Projekt einbinden und in die gegebene Klassenstruktur, wobei ich eigentlich die Funktion runge_kutta(...) global halten möchte, damit sie aus allen Klassen zugänglich ist. Dabei klappt nun die Funktionsübergabe nicht mehr:Zunächst die Funktion die einen Runge-Kutta-Schritt ausführt:
//Differenzialgleichung loesen, nach Runge Kutta //y'(t) = f(t, y(t)) // rechte_seite //h: Schrittweite //y_j: Startwert, bzw. Wert des vorherigen Schrittes //t_j: Zeitpunkt template<typename F> CVektor<double> runge_kutta(F rechte_seite, const double & t_j, const CVektor<double> & y_j, const double & h) { CVektor<double> y_jplus1; const CVektor<double> & k1 = rechte_seite(t_j, y_j); //... y_jplus1 = y_j + h/6*(k1+2*k2+2*k3+k4); return y_jplus1; }
Jetzt der Aufruf der DGL aus einer Klasse void CASMRundstab::loese_dgl() { //... CVektor<double> ergebnis; ergebnis = runge_kutta(rechte_seite_dgl, CZeit::gib_akt_zeit(), startwerte, CZeit::gib_schrittdauer()); //... }
Die Funktion rechte_seite_dgl muss auf Member von CASMRundstab zugreifen und ist daher Member der Klasse:
CVektor<double> CASMRundstab::rechte_seite_dgl(const double & t, const CVektor<double> & y) { CVektor<double> rechte_seite; //... return rechte_seite; }
Das kommentiert der Compiler mit:
error C2064: Ausdruck ergibt keine Funktion, die 2 Argumente übernimmt
Auf die schnelle habe ich versucht, die Funktion runge_kutta auch als Member zu programmieren, aber das funktioniert ebenfalls nicht. Da ist doch irgendwo ein ganz schöner Wurm drin oder?
Vielen Dank.