Forum: PC-Programmierung GNU Libmatheval in C++ Programm anwenden


von gerbej s. (sgerbej)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
  }

von Karl H. (kbuchegg)


Lesenswert?

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

von gerbej s. (sgerbej)


Lesenswert?

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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.