Zwei Fragen zum Zeichnen eines Graphen



  • Hallo freakC++,

    für die Ermittlung der Polstellen habe ich einfach die Fehlerfunktion '_matherr' benutzt, welche eine "Exception" bei allen math. Standardfunktionen auslöst (d.h. dann mach ich nur ein MoveTo, anstatt ein LineTo).

    Und zum Funktionsparser, s. http://www.c-plusplus.net/forum/viewtopic-var-p-is-1780654.html#1780654
    (du kannst die Klasse einfach benutzen, auch wenn du sie inhaltlich wahrscheinlich noch nicht verstehen wirst -)

    Und falls dich der Hintergrund doch noch interessiert, hier ein Artikel zum Funktionsparser (allerdings in C# implementiert): http://www.mycsharp.de/wbb2/thread.php?threadid=71995

    (wenn ich dir jetzt noch sage, daß ich das Graph-Programm innerhalb eines Tages entwickelt habe..., aber das werde ich ja jetzt nicht tun -)



  • Hallo Th69,
    vielen Dank für die Antwort.

    Ja,ja, wenn Du mir sagen würdest, dass Du das innerhalb eines Tages gemacht hast, dann wäre ich ziemlich neidisch. Da ich aber vermute, dass Du auch beruflich in der Richtung tätig bist, ist das für mich ein kleiner Trost, denn das Leben der Berufswelt kommt für mich erst noch. Dann werde ich das innerhalb eines halben Tages machen 😃 😃 😃

    Auf welchem Wissenlevel (Anfang des Studiums, Ende des Studiums, etc) muss man sich befinden, um solch einen Funktionsparser zu schreiben?

    Vielen Dank für eure Hilfe
    lg, freakC++

    edit: die Frage zu _matherr stelle ich im C++ Forum, da dass ja eigentlích nichts mit dem Builder zu tun hat. 🤡



  • Hallo

    freakC++ schrieb:

    Auf welchem Wissenlevel (Anfang des Studiums, Ende des Studiums, etc) muss man sich befinden, um solch einen Funktionsparser zu schreiben?

    Kommt drauf an welche Komplexität der Parser haben soll. Wenn du dich auf Polynome beschränkst, solltest du das ohne ohne Studium hinkriegen. Je mehr mathematische Symbole der Parser erkennen können soll, desto komplexer wird er.

    bis bald
    akari



  • Ok, dann werde ich mir bald das mal näher anschauen. Noch eine ganz andere Frage:

    Ich lasse den Graphen zeichnen, indem ich x / y - Werte mittels zwei Arrays an "DrawGraph" übergebe. Dort wird sofort mit diesen Zahlen gearbeitet.

    Wenn ich nun beispielsweise im Nachhinein (der Graph wurde schon gezeichnet), die Axenbeschriftung ändern muss, so habe ich das berrechnet und dann mit "Invalidate()" meine Komponente aktualisiert. Das Problem ist jedoch, dass dabei der Graph verschwindet. Ich müsste also die x / y - Werte zwischenspeichern und dann den Graphen neuzeichnen lassen. Jetzt meine Frage:

    Ist es eine gute Idee ein dynamisches Array als Member der Komponente anzulegen und darin die Werte zwischenzuspeichern. Außerdem führe ich eine boolsche Variable ein, die per default auf false gesetzt ist. Wenn ich nun Invalidate() ausführe frage ich diese bool variable ab und falls diese true ist, bedeutet das, dass ich den Graphen neu zeichnen muss und die Komponente selbst die DrawGraph Methode ausführt. Wenn ich also einen Graphen zeichnen lasse, dann setze ich die boolsche Variable auf true.

    Ist das eine gute Idee oder gibt es vielleicht eine seriösere? 🙂
    lg, freakC++



  • Hallo nochmal,

    die Funktion '_matherr' wird einfach angesprungen, sobald ein internen math. Fehler auftritt, d.h. du brauchst dort einfach eine globale (bzw. statische) Variable (hier geht es leider nicht anders!) zu setzen und diese dann nach dem Funktionsaufruf abzufragen (vorher natürlich die Variable immer wieder zurücksetzen!).

    Also reicht:

    #include <math.h>
    
    static bool bMathErr = false;
    
    int _matherr (struct _exception *a)
    {
      bMathError = true;
      return 1;
    }
    
    // in your loop:
    
    bMathError = false;
    
    // call math. function (e.g. log(0))
    ...
    
    if(bMathError)
    {
    
    }
    else
    {
    
    }
    

    Und für die Sprünge beim Tangens müßtest du evtl. die Unstetigkeit abfragen (d.h. wenn die Differenz zum letzten y-Wert zu groß ist) - genau weiß ich auch nicht mehr, wie ich das programmiert hatte (Source ist zuhause).

    Und der Funktionsparser beruhte auf einem Compiler (für eine einfache Sprache namens TH-BASIC: eine Mischung aus C und BASIC), welche ich etwa mit 22 Jahren (während meines Vordiploms) entwickelt habe --- hast also noch etwas Zeit -)



  • Hallo

    Ja, du solltest in der Komponente ein dynamisches Array haben, das die Werte speichert.
    Die bool-Variable brauchst du nicht. Denn nach jeder Zustandsänderung durch eine deiner angelegten Eigenschaften solltest du Invalidate oder Refresh aufrufen. Dadurch wird automatisch der OnPaint-Event ausgerufen, in dem dann deine DrawGraph-Methode steht.

    bis bald
    akari



  • Wieso nimmst du nicht einfach TChart oder ähnliches?



  • Ich habe an die bool Variable gedacht, da auch bei anderen Berechnungen Invalidate() aufgerufen wird, doch nicht immer soll ein Graph gezeichnet werden. Wenn ich beispielsweise die Achsenbeschriftung einfach so ändern will, doch es gibt noch gar keinen Graphen, dann dachte ich dass der Aufruf von DrawGraph durch solch eine boolsche Variabl unterdrück werden kann.

    @sonic_1233: Warum sollte ich denn TChart nehmen? Mit TPaintBox kann ich alles machen, was ich will.

    edit: @Th69:
    Das hier scheint aber nicht zu klappen:

    static bool bMathError = false;
    
    int _matherr(struct _exception *a)
    {
     bMathError = true;
     return 1;
    }
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
     double k;
     for (int i = -5; i < 5; i++)
      k = 1/i;
    
     if (bMathError)
     {
      ShowMessage("Ja");
     }
     else
     {
      ShowMessage("Nein");
     }
    
    }
    

    Ich möchte natürlich, dass keine Fehlermeldung mehr kommt. Es wird jedoch eine Exeception vom Builder ausgeführt. Ich dachte, dass diese durch _matherr auch unterdrückt wird. Wie kann ich diese unterdrücken, da ich natürlich keine Exeception sehen möchte, wenn ich den Graphen zu 1/x zeichne.
    Meine Frage ist also, wie ich das obige Programm noch modifizieren muss, dass bei Knopfdruck "Ja" ausgegeben wird (da schließlich durch 0 geteilt wird).



  • Die "_matherror"-Funktion funktioniert natürlich nur für die math. Funktionen (aus <math.h>), nicht für die Integer-Division. Diese läßt sich in C++ gar nicht abfangen, außer durch eine explizite if-Abfrage vorher.



  • Achso, das wusste ich nicht. Dann werde ich wohl mit if Arbeiten, wenn ich durch 0 teilen müsste!

    Vielen Dank
    lg, freakC++



  • Th69 schrieb:

    ..., nicht für die Integer-Division. Diese läßt sich in C++ gar nicht abfangen, außer durch eine explizite if-Abfrage vorher.

    Das ist so nicht ganz richtig. Schau mal in der Hilfe unter "signal" nach.
    Zumindest in meiner BCB6-Hilfe wird da erklärt, wie man einen eigenen Signalhandler implementiert, der auch SIGFPE (unter anderem bei Division durch 0) abfängt.



  • Ok, diese Funktion gibt es, aber sie sollte wirklich nur von Programmierern verwendet werden, die genau wissen, was sie tun - und das scheint mir bei freakC++ noch nicht der Fall zu sein -)

    Obwohl diese Funktion in der Hilfe als "ANSI C" sowie "ANSI C++" kompatibel deklariert ist, scheint sie selbst von den Gurus in den beiden entsprechenden Unterforen nicht benutzt zu werden.


Anmelden zum Antworten