MathPro - Open Source Formelparser

    • Release

    Es gibt 40 Antworten in diesem Thema. Der letzte Beitrag () ist von Damacy.

      MathPro - Open Source Formelparser

      Beschreibung:
      MathPro ist ein Formelparser, der sowohl normale Formeln wie z.B. "sin(45 + 45) -312 * (((3) + 3) / 2)" ausrechnen kann sowie kompliziertere Formeln mit Vektoren.
      Er ist ungefähr 6x schneller als das MSScriptControl und ungefähr doppelt so schnell wie der QuadSoft Expressionparser (s. Beispielprojekt, da ist der Vergleich nochmal leicht möglich).

      Nutzung
      Einen Verweis auf die Lib setzen und dann mit dieser Methode Terme ausrechen lassen:

      Quellcode

      1. public string getResultAsString(string infix)
      2. {
      3. MainExpression.Infix = infix;
      4. MainExpression.Eval();
      5. return MainExpression.Infix;
      6. }

      Oder mit dem oben genannten Übersetzer nach VB übersetzen.
      Wer sich die Vektorrechnung anschauen will sollte sich das Testprojekt downloaden. (Vektoren können nur über die Buttontastatur eingegeben werden)


      Bereits unterstützt
      - Operatoren: +,-,*,/,^
      - Zahlen die in double gespeichert werden können
      - Funktionen: sin,cos,tan,asin,acos,atan, sqrt (Hier wird hin und wieder gerundet, damit man einigermaßen schöne Ergebnisse erhält)
      - Klammern
      - Vektorrechnung

      Lizenz/Weitergabe:
      Open Source. Ihr könnt es meinetwegen fast überall nutzen. Nur bei mobilen Apps mich bitte nochmal anschreiben.
      Mit diesemConverter kann alles ohne Fehler nach VB übersetzt werden.
      Bilder
      • Tester.png

        22,12 kB, 781×462, 375 mal angesehen
      Dateien
      • MathPro.zip

        (171,21 kB, 476 mal heruntergeladen, zuletzt: )
      • MathPro.dll

        (17,41 kB, 302 mal heruntergeladen, zuletzt: )

      Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „Telcrome“ ()

      Telcrome schrieb:

      Er ist ungefähr 6x schneller als das MSScriptControl und ungefähr doppelt so schnell wie der QuadSoft Expressionparser (s. Beispielprojekt, da ist der Vergleich nochmal leicht möglich).

      Battle? :D

      aber ich hab meinen Parser schon vor Jahren geschrieben... ;)

      Trotzdem: Tolle Arbeit !
      Danke^^ Herausforderung steht :D

      Mir ist klar, dass dein Parser schon ein paar Jährchen auf dem Buckel hat, aber ich dachte mir der Vergleich wäre doch ganz interessant, da das MSScriptControl sowieso ziemlich langsam ist und deiner der beste war den ich kannte^^
      Einfach CIL direkt zu schreiben wäre auch zu einfach :D (Falls das gemeint ist)

      Die eigentlichen Zielplattformen meines Parsers sind abgesehen davon Windows Phone und Windows RT. Von daher kann ich solche Funktionen gar nicht nutzen^^

      Habe jetzt mal einen neuen Konstruktor implementiert, bei diesem Aufruf:

      Quellcode

      1. MathPro.Parser = new MathPro.Parser(true);

      Rundet MathPro die trigonometrischen Funktionen nicht mehr.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Telcrome“ ()

      Bei sowas krieg ich schon die Krise :D

      Quellcode

      1. bool CharIsNumber(char testChar)
      2. {
      3. switch (testChar)
      4. {
      5. case '0':
      6. case '1':
      7. case '2':
      8. case '3':
      9. case '4':
      10. case '5':
      11. case '6':
      12. case '7':
      13. case '8':
      14. case '9':
      15. return true;
      16. default:
      17. return false;
      18. }
      19. }
      20. /**/
      21. bool CharIsBracket(char testChar)
      22. {
      23. if (testChar == '(' || testChar == ')')
      24. {
      25. return true;
      26. }
      27. else
      28. {
      29. return false;
      30. }
      31. }
      Warum hast du CharIsBracket nicht wie CharIsComma gemacht? CharIsNumber sollte nur ein Bereich checken sein als jede Möglichkeit zu überprüfen.


      Quellcode

      1. if (sA[myIndex] == 'S' && sA[myIndex + 1] == 'I' && sA[myIndex + 2] == 'N')
      2. {
      3. return true;
      4. }
      Ist doch auch Bullshit. Sammel die Buchstaben. Sobald dann die Klammer kommt guckst du ob du eine Funktion mit so einem Namen hast (variable Anzahl von Funktionen).


      Quellcode

      1. else if (CharIsOperator(myArray[i]) == true)
      2. {
      3. if (i > 0)
      4. {
      5. if (CharIsOperator(myArray[i - 1]) == true || CharIsBracket(myArray[i - 1]) == true)
      6. {
      7. UseExpression.ReverseActualPrefix();
      8. }
      9. else
      10. {
      11. UseExpression.AppendMathOperator(myArray[i].ToString());
      12. }
      13. }
      14. else
      15. {
      16. UseExpression.ReverseActualPrefix();
      17. }
      18. }
      Booleans testen? :thumbdown: Und bei jedem Operator soll das Vorzeichen geändert werden (wenn ich das richtig verstehe)?


      Quellcode

      1. double Degrees(double degree)
      2. {
      3. return degree / (180 / Math.PI);
      4. }
      5. double Radiants(double Radiant)
      6. {
      7. return Radiant * (180 / Math.PI);
      8. }
      Und aus einem Degree machst du mehrere Degree und aus einem Radiant Radianten?
      Sooo viel kann da noch getan werden.
      @Mangafreak1995
      Okay schonmal danke, dass du dich ein bisschen damit befasst hast :)

      CharIsBracket hab ich jetzt gekürzt.
      Neues CharIsNumber:

      Quellcode

      1. bool CharIsNumber(char testChar)
      2. {
      3. Int32 TestInt = Convert.ToInt32(testChar);
      4. return (TestInt >= 48 && TestInt <= 57);
      5. }


      Beim zweiten:
      Das ändere ich, sobald ich die Architektur des Übersetzers überarbeite (Betrifft ja nicht den eigentlichen Rechner an sich, sondern nur den Teil zur Übersetzung der Infixnotation.

      Da weiß ich gerade nicht genau was an dem Code falsch bzw. nicht ideal ist. Meinst du die Angewohnheit immer noch ein == true hinter booleans zu setzen?

      Und das mit den Operatoren und Reverseprefix hast du falsch verstanden.
      Wenn man z.B. schreibt 3*-3, dann kann der Parser das ausrechnen. Ergebnis: -9
      Das Vorzeichen muss nämlich einfach immer geändert werden, wenn der Char vor dem Minus ein Operator war^^

      Der letzte Codeausschnitt von dir übernimmt die Umrechnung von Bogenmaß in Grad, da seh ich eigentlich auch keinen Fehler. Nur die Bennenung der Parameter ist verwirrend, ist wohl durch eine Suchen & Ersetzen Aktion entstanden.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Telcrome“ ()

      Wieso nimmst du nicht gleich Char.IsDigit/.IsNumber?
      „Was daraus gefolgert werden kann ist, dass jeder intelligentere User sein Geld lieber für Bier ausgibt, um einen schönen Rausch zu haben, und nicht dieses Ranzprodukt.“

      -Auszug aus einer Unterhaltung über das iPhone und dessen Vermarktung.

      Lukas schrieb:

      Wieso nimmst du nicht gleich Char.IsDigit/.IsNumber?

      Danke, damit läuft es jetzt viel unkomplizierter :thumbsup:


      jvbsl schrieb:

      Vorallem ist Convert langsam. Sollte bei C# und char nicht auch nen cast gehen?

      Habe ich mal ausprobiert, hat aber keinen wirklichen Geschwindigkeitsunterschied gegeben. Habe jetzt die Lösung von Lukas genommen, auch auf die Gefahr hin, dass ich das auf anderen Plattformen nicht auf diese Weise nutzen kann


      Ich werde nachher mal die neue Version (Dann auch mit Vektorrechnung) hochladen, aber aktuell werden negative Zahlen nicht ausgerechnet und ich weiß leider nicht wieso :D
      @Lukas: Wohl nur Char.IsDigit, IsNumber gibt zum Beispiel auch bei Chinesischen Schriftzahlen True zurück.

      @jvbsl: Jo, eigentlich kann man explizit casten oder einen impliziten Cast verwenden. Achtung: Mono kann den impliziten Cast nicht. (siehe hier) Offensichtlich kann Mono es mittlerweile.
      Von meinem iPhone gesendet
      Hallo,
      sieht ganz nett aus ;) Habe das gleich mal getestet, bekomme hierbei zum Beispiel aber leider einen Fehler:
      (3+5-34*(-3)+(-45))/((-1)*5*3*66/33*345-33+4/4)
      Wenn ich die Testanwendung so starte, kommt einfach nur "Das programm funktioniert nicht mehr".
      Mit Visual Studio kommt es in Zeile 436 von Parser.cs zu folgender Fehlermeldung:
      "Der Index lag außerhalb des Bereichs. Er muss nicht negativ und kleiner als die Auflistung sein."
      Stimmt da was an meiner Eingabe nicht?
      Außerdem könnte man doch sowas viel komfortabler mit Objektorientierung lösen, oder? Du erstellst verschiedene Klassen, die für einen Operator oder eine Zahl stehen und erstellst beim Parsen eine Liste davon.
      Den Code, den deine Libary erzeugt, kann man doch sowieso nicht einfach so lesen, da er viel zu unübersichtlich ist. (Ich denke aber mal, dass er auch nicht dazu dienen soll)
      mfg
      Suscurtl
      Danke schonmal für den Bugreport. Der Bug entsteht dadurch, dass im letzten Update anscheinend (-1) keine Zahl ist, sondern eine Rechnung null - 1. Von daher kann das ganze nicht ausgerechnet werden.
      Ich werde das mal fixen

      Die Parserlanguage habe ich mir eigentlich nur zur Kommunikation ausgedacht und sie ist wirklich auf keinen Fall dazu gedacht, dass die ein Mensch lesen soll :D

      OOP wurde exakt so umgesetzt wie du geschrieben hast...

      Im nächsten Update kann dann auch mit Vektoren aus dem Term gerechnet werden.