Übergabe einer Funktion per Tastatur



  • mitglied2347 schrieb:

    Wen es interessiert, das gesamte Programm sieht so aus. Kritik, Anregung zum Quelltext sind auch erwünscht

    Frag dich mal, ob es wirklich nötig ist, 10000 double's im Speicher zu halten.
    🙂



  • Mit Interpretern EMCAScripts oder Lua kenne ich mich leider überhaupt nicht aus... 😞



  • mitglied2347 schrieb:

    Mit Interpretern EMCAScripts oder Lua kenne ich mich leider überhaupt nicht aus... 😞

    Wenn du nicht allzuviele Operationen umsetzen willst, könntest du auch schnell selbst was schreiben. Das wird aber sicher umfangreicher als der Rest. Da war erst neulich was:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-262782.html

    Vielleicht bekommst du's einfacher hin, wenn du eine andere Notation einführst. Infix ist nicht unbedingt leicht zu parsen.
    🙂



  • µngbd schrieb:

    mitglied2347 schrieb:

    Wen es interessiert, das gesamte Programm sieht so aus. Kritik, Anregung zum Quelltext sind auch erwünscht

    Frag dich mal, ob es wirklich nötig ist, 10000 double's im Speicher zu halten.
    🙂

    ne nötig nicht, aber das ganze ist ja auch nicht für einen echtzeitsteuerung gedacht, sondern nur just for fun...



  • mitglied2347 schrieb:

    Das Problem ist nur, dass ich die zu integrierende Funktion immer mit in den Quelltext schreiben muss.

    Schreib einfach einen kleinen Parser, der dir aus dem eingegebenen Ausdruck einen Syntaxbaum macht, den du dann für jeden Variablenwert rekursiv auswerten kannst.

    Das ist natürlich nicht so effizient; statt einen paar Instruktionen, die dir gleich das Ergebnis ausrechnen, hast du dann einen Haufen einzelne Funktionsaufrufe für die ganzen Additionen und Multiplikationen usw., die in dem Ausdruck vorkommen. Du kannst es eventuell noch etwas optimieren, indem du bestimmte Teile des Baums vereinfachst, also z.b. Polynonome erkennst und die dann direkt ausrechnest.

    Aber wenn es wirklich so effizient wie möglich sein soll, bleibt nur die Möglichkeit, mit dem eingegebenen Ausdruch einen Compiler aufzurufen, der dir wirklich Code erzeugt. Das ist natürlich irgendwie eklig sowas zur Laufzeit zu machen.



  • Naja, die Kirche kann meines Erachtens vorläufig durchaus im Dorf bleiben; für diesen Fall dürfte der shunting yard algorithm eigentlich locker ausreichen.

    Auch ist er deutlich einfacher zu bewältigen als ein LL-Parser, was - ich entschuldige mich, mitglied2347, wenn ich deinen Kenntnisstand hier falsch einschätze - ein großer Vorteil sein dürfte. Rekursive Parser sind keine ganz simple Geschichte.



  • wie funktioniert denn so ein algorithmus kurz wörtlich beschrieben. Bei Wikipedia steht ja nur, wie es sortiert wird. Irgendwie müssen die Daten ja von der Eingabe dorthin gelangen, wo ich normalerweise, meine Gleichung in den Quelltext schreibe.



  • Die Daten werden als Zeichenkette (char Array) eingelesen und in ihre Bestandteile aufgeteilt ( geparst ).



  • Naja, letzten Endes schmeißt dir der Algorithmus die Gleichung in RPN aus, was ziemlich einfach auszuwerten ist. Letztendlich wird das im Code wohl etwa auf

    double evaluate_rpn(struct token rpn[], double x) {
      /* Auswertung hier */
    }
    

    hinauslaufen. Die Tokens selber musst du dir aus der Eingabe fummeln. Für einen einfachen Fall ohne Funktionstoken (wie sin, cos, etc.) kann das etwa so aussehen:

    static char const *const op_chars = "+-*/^()";
    
    enum token_type {
      tok_num,
      tok_op,
      tok_x
    };
    
    struct token {
      union {
        double num;
        char   op;
        char   var;
      } v;
    
      enum token_type type;
    };
    
    struct token *get_token(char const **pos, struct token *dest) {
      int n;
      double num;
      char const *line = *pos;
    
      while(line[0] == ' ') {
        ++line;
      }
    
      if(strchr(op_chars, line[0]) != NULL) {
        dest->v.op = line[0];
        dest->type = tok_op;
        *pos = line + 1;
      } else if(tolower(line[0]) == 'x') {
        dest->type = tok_x;
        *pos = line + 1;
      } else if(sscanf(line, "%lf%n", &num, &n) == 1) {
        dest->v.num = num;
        dest->type = tok_num;
        *pos = line + n;
      } else {
        return NULL;
      }
    
      return dest;
    }
    

    Aufruf dann etwa

    char *pos = line; /* line sei die eingelesene Zeile */
    struct token tok;
    
    while(get_token(&pos, &tok)) {
      /* Token verarbeiten */
    }
    


  • ok, der post kam etwas zu spät....

    aber wie wird aus den Daten wiederum code?? wenn ich eine Gleichung wie y=2x+4*cos(x) in einem String einlese, dann kann ich die einzelnen bestandteile in bestimmte typten aufteilen: Ziffern, Variablen, Operatoren. Bis dahin verstehe ich das.

    Aber wie setze ich das dann wieder so zusammen, dass damit gerechnet werden kann. Es bei mir nämlich so, dass ich für das x ein array einsetze, bei dem ich mit einer schleife bestimme, welches Element gerade ausgelesen wird. Ich möchte für jeden verschiedenen Zähler in meiner Schleife verschiedene Ergebnisse der Gleichung erhalten.



  • [quote="mitglied2347"]ok, der post kam etwas zu spät....

    aber wie wird aus den Daten wiederum code??[quote]
    Gar nicht. Du musst sie interpretieren.
    🙂



  • Letztendlich liefert dir der Shunting-Yard-Algorithmus eine Queue (wahlweise ein Array oder eine Liste) von Token, die die eingegebene Funktion in umgedrehter polnischer Notation bezeichnen. Was das ist und wie einfach die auszuwerten ist, steht im entsprechenden Wikipedia-Artikel, der vom Shunting-Yard-Algorithmus-Artikel, den ich hier verlinkt habe, verlinkt ist, beschrieben.

    Es ist möglich, den Shunting-Yard-Algorithmus so anzupassen, dass er direkt rechnet, aber da du die Funktion hier ja mehrmals mit verschiedenen x-Werten auswerten willst, macht das wenig Sinn.


Anmelden zum Antworten