Hallo zusammen!
ich habe ein kleinclass geschrieben.zwei Methoden von diesem Class
sollten Werte an X und y Pair in globale Struct zuweisen :
class.h 1 | struct XYpair{
| 2 | double x;
| 3 | double y;
| 4 | };
| 5 |
| 6 | class INPUT{
| 7 |
| 8 | private:
| 9 | int psize;
| 10 | double xmin,xmax;
| 11 | XYpair* ptr;
| 12 | int intep;
| 13 | int dacrate;
| 14 | int ns;
| 15 | public:
| 16 | void setvalue();
| 17 | XYpair* Dezim(int& psize, XYpair* ptr);
| 18 | XYpair* Interp(int& ns, XYpair* ptr);
|
class.pp 1 | XYpair* INPUT::Dezim(int& psize, struct XYpair* ptr){
| 2 |
| 3 | double xr=xmax-xmin/psize;
| 4 | double X=0.0;
| 5 | int i;
| 6 | XYpair *dptr= new XYpair [psize];
| 7 | for(i=0;i<psize;i++){
| 8 | dptr[i].x=X;
| 9 | dptr[i].y=sin(X); <-----//mit f_eingeben() auswerten
| 10 | X+=xr;
| 11 | }
| 12 | return dptr;
| 13 | }
| 14 |
| 15 | XYpair* INPUT::Interp(int& ns, XYpair* ptr){
| 16 |
| 17 | double xr=(double)(intep*4/dacrate);
| 18 | XYpair *iptr;
| 19 | iptr=new XYpair[ns];
| 20 | int i;
| 21 | for(i=0;i<ns;i++)
| 22 | {
| 23 | iptr[i].x=xr;
| 24 | iptr[i].y=sin(iptr[i].x*i); <-----//mit f_eingeben() auswerten
| 25 | xr++;
| 26 | }
| 27 | delete[]iptr;
| 28 |
| 29 | }
|
nun möchte ich die Werte durch eine Funktion, die ich über Konsole
eingebe,erstmal auswerten und dafür benutze GNU Libmathavel(C-
Bibleotheck), die der eingegebenen mathematischen Funktionen für
spezifizierte variable Werte auswerten kann; ich habe sie in
Funktionparser schön verwendet;
hier ist die funktionsparser:
1 | void f_eingeben(){
| 2 |
| 3 | char buffer[BUFFER_SIZE];
| 4 | int length;
| 5 | void *f;
| 6 | char **names;
| 7 | int count j,i;
| 8 | double X;
| 9 | double *x_f;
| 10 | cout <<"f(x_f) = ";
| 11 | cin.getline(buffer, BUFFER_SIZE);
| 12 | length = strlen (buffer);
| 13 | if (length > 0 && buffer[length - 1] == '\n')
| 14 | buffer[length - 1] = '\0';
| 15 |
| 16 | f = evaluator_create (buffer); /* Create evaluator for function. */
| 17 | assert (f);
| 18 | /* Print variable names appearing in function. */
| 19 | evaluator_get_variables (f,&names, &count);
| 20 | cout <<" " ;
| 21 | for (j = 0; j < count; j++)
| 22 | // printf ("%s ", names[j]);
| 23 | cout <<'\n';
| 24 |
| 25 | double* y= new double [N_SAMPLES];
| 26 | double X=0.001;
| 27 | for(j=0;j<=N_SAMPLES-1;j++){
| 28 | // Funktion evalutator_evaluate_x() zur Auswertung von f(x)
| 29 | y[j]=evaluator_evaluate_x (f,X);
| 30 | X=X*j;}
| 31 |
| 32 | /* Destroy evaluators. */
| 33 | evaluator_destroy (f);
|
Nun meine Frage wie Kann ich die f_eingeben () in meiner classmathoden
verwenden (classmethod:dezim() gibt Funktionsplottwerte zurück und
inter() liefert Funcktionstransmittwerte);
ich überlege mir die f_eingeben() als golable funktion zu definieren;
aber ich weis nicht wie die in Dezim() bzw interp() aufrufen kann;
also wenn man eine Idee für mich hat wie ich meine Aufgaben lösen kann
dann bin sehr Dankbar.
Gruß
Sgerbej
gerbej seb schrieb:
> XYpair* Dezim(int& psize, XYpair* ptr);
> XYpair* Interp(int& ns, XYpair* ptr);
einen int per Referenz zu übegreben ist nicht sehr sinnvoll.
> Nun meine Frage wie Kann ich die f_eingeben () in meiner classmathoden
> verwenden
natürlich.
> ich überlege mir die f_eingeben() als golable funktion zu definieren;
> aber ich weis nicht wie die in Dezim() bzw interp() aufrufen kann;
einfach aufrufen.
Solange ein Funktionsprototyp dafür sichtbar ist, gibt es kein Problem.
Nur weil C++ Klassen hat, heißt das noch lange nicht, dass jede Funktion
in einer Klasse stecken muss. Es gibt auch freistehende Funktionen, die
keiner Klasse zugeordnet sind, so wie es sie auch in C gab. Du rufst ja
sin() auch einfach auf, ohne dir Gedanken darum zu machen ob die in
einer Klasse steckt oder nicht.
Aber ich denke ernsthaft, dass es besser wäre, eine Evaluierungsfunktion
(private oder protected Funktion) in deiner INPUT Klasse zu schreiben
und so eine stärkere Bindung zu erreichen. INPUT hat eine Methode, mit
der sie einen String übernimmt, der als auszuwertender Ausdruck
gespeichert wird. Und in der Eval Funktion wird der dann ausgewertet.
Auf die Art soll, nein muss, sich INPUT nicht damit herumschlagen, wo
denn dieser String eigentlich herkommt. Das geht diese Klasse nichts an
und ist nicht ihr Bier. Sie bekommt diesen String und soll Wertepaare
dafür auswerten. Also: Ein/Ausgabe von den Arbeitsfunktionen trennen.
1 | double xr=xmax-xmin/psize;
|
ich denke, du wolltest eigentlich 1 | double xr = ( xmax-xmin ) / psize;
|
und X dann mit dem Wert xmin starten lassen.
1 | for(i=0;i<psize;i++){
| 2 | dptr[i].x=X;
| 3 | dptr[i].y=sin(X); <-----//mit f_eingeben() auswerten
| 4 | X+=xr;
| 5 | }
|
Das ist nicht so schlau. Denn in einem Computer gibt es ein Problem:
Begrenzte Rechengenaugikeit.
In dieser Aufsummierung landest du am Ende irgendwo, aber sicher nicht
am Endwert. Zumindest nicht exakt. Wenn du in einer Schleife beginnend
bei 0.0 immer 0.001 dazuzählst, und das 1-tausend mal. Dann hast du am
Ende nicht 1.0 erreicht sondern 0.99999 und das ist nun mal nicht 1.0
(ein Vergleich auf 1.0 schlägt fehl)
Besser ist es, keinen derartigen aufsummierenden Fehler zuzulassen 1 | for(i = 0; i < psize; i++ ) {
| 2 | dptr[i].x = xmin + i * xr;
| 3 | dptr[i].y = sin( dptr[i].x );
| 4 | }
|
Ein weiteres "organisatorisches" Problem:
Es ist nie besonders schlau, new und den zugehörigen delete auseinander
zu reissen.
wie zb hier 1 | XYpair* INPUT::Dezim(int& psize, struct XYpair* ptr){
| 2 |
| 3 | double xr=xmax-xmin/psize;
| 4 | double X=0.0;
| 5 | int i;
| 6 | XYpair *dptr= new XYpair [psize];
| 7 | for(i=0;i<psize;i++){
| 8 | dptr[i].x=X;
| 9 | dptr[i].y=sin(X); <-----//mit f_eingeben() auswerten
| 10 | X+=xr;
| 11 | }
| 12 | return dptr;
| 13 | }
|
wo ist der zugehörige delete[] ?
Die Antwort ist: du kannst ihn hier nicht machen, sondern musst darauf
vertrauen, dass ihn der Aufrufer erledigen wird.
Das ist aber nicht besonders gut. Besser ist es, wenn du das so
gestalten kannst, dass der Aufrufer eben nicht vergessen kann. Und an
dieser Stelle kommen Container ins Spiel.
C++ gibt dir bereits Container an die Hand. zb einen std::vector.
Benutze sie, sie vereinfachen dein Leben. WEnn die Funktion einen
std::vector<XYpair> zurückliefert, dann KANN der Aufrufer nicht
vergessen, den Speicher freizugeben. Der std::vector kümmert sich darum!
Sobald er ausser Scope geht, gibt er den allokierten Speicher frei.
C++ leidet immer noch unter dem Ruf, dass dynamische Speicherverwaltung
so wahnsinnig kompliziert wäre und man so wahnisnnig aufpassen muss.
Darum wurden Garbage Collectoren entwickelt, die hinter einem aufräumen.
Dabei ist es in C++ mit seinen Möglichkeiten relativ einfach, ein System
hochzuziehen, in dem die Klassen selber hinter sich aufräumen. Man muss
nur ein wenig seine C Gewohnheiten über Bord werfen und dann wird
dynamisches Speichermanagement relativ einfach und auch zuverlässig. Und
zwar ohne dass die Speicherbelastung erst mal auf ein paar Gigabyte
anwachsen muss, ehe sich dann der GC erbarmt und aufräumt.
Daher:
std::string, std::vector, std::list und all die anderen Template Klassen
sind deine Freunde. Benutze sie! Auch wenn man immer wieder mal andere
Meinungen hört: Es gibt keinen Grund, um Container einen Bogen zu machen
und sich selber um die Allokierungen zu kümmern.
1 | #include <vector>
| 2 |
| 3 | std::vector<XYPair> INPUT::Dezim( int psize )
| 4 | {
| 5 | double xr = ( xmax-xmin ) / psize;
| 6 | std::vector<XYPair> result;
| 7 |
| 8 | for( int i = 0; i < psize; i++ )
| 9 | {
| 10 | double X = xmin + i * xr;
| 11 | result.push_back( XYPair( X, sin( X ) );
| 12 | }
| 13 | return result;
| 14 | }
|
Verwendung: 1 | void foo()
| 2 | {
| 3 | std::vector<XYPair> values;
| 4 | INPUT wasAuchImmer;
| 5 |
| 6 | ....
| 7 |
| 8 | values = wasAuchImmer( 25 );
| 9 |
| 10 | ...
| 11 | } // mit Beendigung der Funktion räumt der std::vector selbsttätig den
| 12 | // Speicher auf. Keine Speicher Löcher
|
Hallo zusammen!
Danke sehr Karl für deine ausführliche Erklärung; ich habe mein Code
nach deiner Vorschläge geändert und es gut std:: vector gut geklappt.
Nun versuche ich die C-Library zu verwenden; ich habe eine nue Funktion
f_eingeben()
für die mathematische funktion,die ich über konsleeingebe, zugefügt;
aber weis nicht ob es so laufen würde,denn ich habe da Problem mit der
linke weis jamend wie ich die in Makefile den linke übergeben kann?
hier ist class.h: 1 |
| 2 | #define BUFFER_SIZE 200
| 3 |
| 4 | using namespace std;
| 5 |
| 6 |
| 7 | struct XYpair{
| 8 | double x;
| 9 | double y;
| 10 | XYpair(double x, double y):x(x),y(y){}
| 11 | };
| 12 |
| 13 | class INPUT{
| 14 |
| 15 | private:
| 16 | int psize,ns;
| 17 | double xmin,xmax;
| 18 | //XYpair* ptr;
| 19 | std::vector<XYpair> dptr;
| 20 | int intep;
| 21 | int dacrate;
| 22 |
| 23 | //int BUFFER_SIZE=200;
| 24 | char buffer[BUFFER_SIZE];
| 25 | int length;
| 26 | void *f;
| 27 | char **names;
| 28 | int count;
| 29 | double X;
| 30 | double *x_f;
| 31 |
| 32 | public:
| 33 | void setvalue();
| 34 | //XYpair* Dezim(int& psize, XYpair* ptr);
| 35 | //XYpair* Interp(int& ns, XYpair* ptr);
| 36 |
| 37 | std::vector<XYpair> Dezim(int psize);
| 38 | std::vector<XYpair> Interp(int ns);
| 39 | void setvalue_int();
| 40 |
| 41 | protected:
| 42 | void f_eingeben();
| 43 |
| 44 | };
|
abschnitt von class.cpp 1 | void INPUT::f_eingeben(){
| 2 |
| 3 | cin.getline(buffer, BUFFER_SIZE);
| 4 | length = strlen (buffer);
| 5 | if (length > 0 && buffer[length - 1] == '\n')
| 6 | buffer[length - 1] = '\0';
| 7 |
| 8 | f = evaluator_create (buffer); /* Create evaluator for function. */
| 9 | assert (f);
| 10 | /* Print variable names appearing in function. */
| 11 | evaluator_get_variables (f,&names, &count);
| 12 | cout <<" " ;
| 13 | for (j = 0; j < count; j++)
| 14 | // printf ("%s ", names[j]);
| 15 | cout <<'\n';
| 16 |
| 17 | /* Destroy evaluators. */
| 18 | evaluator_destroy (f);
| 19 | }
| 20 |
| 21 |
| 22 | std::vector<XYpair> INPUT::Dezim(int psize){
| 23 |
| 24 | double xr=(double)(xmax-xmin)/psize;
| 25 | double X=xmin;
| 26 | int i;
| 27 | std::vector<XYpair> dptr;
| 28 | X=xmin;
| 29 | for(i=0; i<psize; i++){
| 30 | dptr.push_back(XYpair(X,evaluator_evaluate_x (f,X)));
| 31 | X+=xr;
| 32 | }
| 33 | return dptr;
| 34 | }
| 35 |
| 36 |
| 37 | std::vector<XYpair> INPUT::Interp(int ns){
| 38 |
| 39 | double xr=(double)intep*4/dacrate;
| 40 | std::vector<XYpair> iptr;
| 41 | for(int i=0 ; i<ns; i++){
| 42 | iptr.push_back( XYpair(i*xr,evaluator_evaluate_x(f,xr*i)));
| 43 | }
| 44 | return iptr;
| 45 | }
|
Abschnitt main.cpp 1 |
| 2 | extern "C" {
| 3 | #include <matheval.h>
| 4 | }
| 5 |
| 6 | using namespace std;
| 7 |
| 8 | int main(){
| 9 | int ns=20;
| 10 | int psize=15;
| 11 | std::vector<XYpair> V;
| 12 | INPUT Func;
| 13 |
| 14 | Func.f_eingeben();
| 15 | int wahl;
| 16 |
| 17 | cout << ":2 für Dezimat() und 1 für Interp():";
| 18 | cin >> wahl;
| 19 | if(wahl==1){
| 20 | Func.setvalue_int();
| 21 | // M=Func.Interp(ns,v);
| 22 | V =Func.Interp(ns);
| 23 | for(int i=0;i<ns-1; i++){
| 24 | cout <<"V.x"<<V[i].x<<"V.y"<<V[i].y<<'\n';
| 25 | }
|
Makefile 1 | project:project.o main.o
| 2 | g++ -o project project.o main.o
| 3 |
| 4 | project.o:project.cpp project.h
| 5 | g++ -c project.cpp
| 6 |
| 7 | main.o:main.cpp project.h
| 8 | g++ -c main.cpp
| 9 |
| 10 | clean:
| 11 | rm project project.o main.o
| 12 |
| 13 | #that's all
|
paare Fehlermeldung: 1 | error: âevaluator_createâ was not declared in this scope
| 2 | project.cpp:30:12: error: âassertâ was not declared in this scope
| 3 | project.cpp:32:44: error: âevaluator_get_variablesâ was not declared in this scope
| 4 | project.cpp:34:8: error: âjâ was not declared in this scope
|
Danke schönmal im Voraus für jede Hilfe
Gruß
Seb
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|