AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Mathem. Parser -- bitte testen
Thema durchsuchen
Ansicht
Themen-Optionen

Mathem. Parser -- bitte testen

Ein Thema von dizzy · begonnen am 23. Mai 2004 · letzter Beitrag vom 2. Okt 2013
Antwort Antwort
Seite 6 von 11   « Erste     456 78     Letzte »    
Benutzerbild von dizzy
dizzy
Registriert seit: 26. Nov 2003
Hi DPler!

Ich habe noch so einiges an meinem Parser (hier schon mal vorgestellt) verbessert/geändert.

Habe jetzt auch ein Testprogramm geschrieben. Es führt einige Rechnungen durch, und gibt eine kleine Statistik dazu aus. Folgende Infos von euch würden mich brennend interesieren:
  • welche Dephi-Version hast du?
  • läufts/compilierts damit?
  • sind die Ergebnisse im Testprog korrekt?
  • CPU-Typ + Realtakt
  • die Ergebnisse der Geschwindigkeitsmessung des Testprogs
  • ist die Implementierung hübsch und sauber? (keine Leaks, styleguidekonform, verwendete Techniken...)
    (in CQParser.pas bzw. der QMath(2).pas - nicht das Testprog. Das ist fix zusammengeschustert )
  • hälst du den Parser für sinnvoll/einsetzbar?
  • Verbesserungs- und/oder Verschönerungs- und/oder Verschnellerungsvorschläge?
Wer Lust hat, der kann ihn sehr gerne komplett auseinandernehmen und kaputttesten. Ich will alles wissen *g*.

Ich erwarte sicherlich nicht von jedem alles beantwortet. Mir geht es hauptsächlich darum zu sehen mit welchen D-Versionen und CPUs der Parser korrekt arbeitet, und wie schnell er es tut (im Vergleich zu einer hardgecodeten Rechnung).

Tipp für die D8-User: Es gibt die Units "QMath" und "QMath2". Ändert im QT des Parsers und des Testprogramms in der uses-Klausel "QMath" auf "QMath2", weil "QMath" verwendet z.T. Assembler. Ich hoffe dass D8 die ganzen Casts zulässt . Wenn nicht, dann schreit!

Ihr würdet mir einen Riesen-Gefallen tun!

Danke euch schonmal im Voraus,
MfG - dizzy


\\div. Edits: Ein paar Umformulierungen - nix wildes...
Angehängte Dateien
Dateityp: zip cqparser.zip (17,9 KB, 584x aufgerufen)
INSERT INTO HandVonFreundin SELECT * FROM Himmel
 
Kastor
 
#51
  Alt 7. Jul 2004, 16:38
Hi,

- Delphi7 Professional (kompiliert ohne Probleme)
- Ergebnisse sind korrekt
- Amd Athlon 2800+, gibt so um die 2 Ghz Realtakt

Ergebnisse (von oben nach unten):
850,968
1478,88
3733,95
6893,12

Gruß, Kastor
  Mit Zitat antworten Zitat
neolithos

 
Delphi 7 Architect
 
#52
  Alt 7. Jul 2004, 17:14
  • Delphi 7 Prof
    Celeron 1 GHz
    1633,33
    3007,94
    6480,49
    12938,5

Kritik: Der Parser ist sehr ausprogrammiert und schlecht erweiterbar.

Schau die mal ein paar Seiten zum Thema Compilerbau, Deterministisch Endlicher Automat, Optimierung, ZwischenCode usw. an.

Denn in dem Copy&Paste-Code möchte ich nie etwas ändern.
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

 
Delphi 7 Enterprise
 
#53
  Alt 7. Jul 2004, 17:32
Zitat von neolithos:
Kritik: Der Parser ist sehr ausprogrammiert und schlecht erweiterbar.
Eigentlich nicht. Zur Erweiterung genügt es zb. einen neuen Operator einzufügen, und dessen Behandlung in den großen "if..then..else"-Zweig einzusetzen. Zwar muss man etwas darauf achten, wo man diese Behandlung einfügt, aber ich hab ihn ja ständig selbst erweitert - z.B. kennt er mittlerweile Konstanten wie pi oder e.
Ihn voll "customizable" zu machen, das wollte ich nicht, da dass erheblich an der Performance gedrückt hätte, und ich wollte das Teil so schnell wie auch nur irgend möglich machen. Das war im Gegensatz zur Erweiterbarkeit oberstes Ziel, daher auch meine Testreihe hier.
Habe das Ding jetzt sogar in eine DLL verpackt, so dass das mit der Erweiterbarkeit ohnehin flach fällt, man ihn aber in beliebigen Sprachen einsetzen kann (die DLLs einbinden können...).

Ein paar kleine Finetunings sind noch nötig, und dann werd ich den nochmal komplett mit Source+DLL hier einstellen. Und es sollte garnicht nötig sein ihn zu erweitern, da ich eigentlich so ziemlich alle Grundoperationen drin hab, incl. der eigentlich nie gebrauchten trigonometrischen Funktionen für Quaternionen

Speed war deshalb oberstes Gebot, da ich mit dem Teil 3D-Fraktale berechne, und da kommen sehr leicht > 10.000.000 Rechendurchläufe pro Formel rum.

Wenn diverse Funktionen fehlen sollten, die ihr vermissen würdet, so bin ich offen für Vorschläge! Das Dingen sollte nachher als Monolit dastehen, d.h. fertig und rund. Zwar OpenSource, aber nicht mit der Notwendigkeit dran rumzufummeln . Wobei das wie gesagt garnicht so unmöglich ist .

Danke aber für den Tipp, ich hatte diesen Aspekt noch nicht als einzelnes betrachtet.


grüzli,
dizzy
Fabian K.
  Mit Zitat antworten Zitat
neolithos

 
Delphi 7 Architect
 
#54
  Alt 7. Jul 2004, 17:52
Genau so könnte man aber Speed rausholen.


Grund: Wenn du die Formel zu einer schnell durchrechenbaren Sprache umcompilierst und opimierst, vermute ich, dass das Teil schneller wird.

Bei Meinem Formel-Parser (der langsamer ist, durch Typenkonvertierungen und OOP) gehe ich wie folgt vor.

(1 + sin(A))^3 * (1+1)

Erster Schritt:

zerlegen in Token (Teile):

"1" "+" "sin" "(" "A" ")" "^" "3" "*" "(" "1" "+" "1" ")"
Dies erledigt eine while Schleife gekoppelt mit einer Matrix.

Baue aus den Tokens einen Parsebaum:

Dazu wird ein vor definierter Syntax-Graph durchlaufen.
-> Wieder nur eine while-Schleife

Optimiere den Code:
in dem Fall wird 1+1 zusammengefasst.

Erzeuge Code:

Code:
push 1
push a
sin
and
push 3
power
push 2
mul
Und die Ausführung dieses Code's könnte man extrem Optimieren.
Array für Stack.
Sprung-Tabelle für Proceduren.
  Mit Zitat antworten Zitat
ripper8472
 
#55
  Alt 7. Jul 2004, 19:38
@neolithos:

deinen Ansatz mit den bäumen verfolge ich auch gerne, besonders in PHP. Was ich persönlich nicht verstanden habe ist dein erzeugter code mit "pushes", deren verwendung mir nicht klar ist (sieht nicht wie assembler aus).

greets ripper

(sorry für mein gelaber)
Christoph
  Mit Zitat antworten Zitat
neolithos

 
Delphi 7 Architect
 
#56
  Alt 7. Jul 2004, 20:09
Das ist auch keine Assembler sonder eine eigene Sprache.

Sie basiert auf einem Stack. -> Stackmaschine.

push 1 --> legt 1 auf den Stack
push 4 --> legt 4 auf den Stack
and --> nimmt zwei Werte vom Stack, Addiert sie und legt das Ergebnis auf den Stack.
  Mit Zitat antworten Zitat
ripper8472
 
#57
  Alt 7. Jul 2004, 23:32
Hi,

ich war noch etwas verwirrt, weil ich bei den Tokens keine Klammern um die 1 und das Sinus gesehen hab. So ein Stacksytem ist echt nicht schlecht!

An solche Bäume lassen sich auch symbolische Umformungen ansetzen: ein Computer Algebra System!!

- ripper

(sorry für meine verwirrten posts)
Christoph
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

 
Delphi 7 Enterprise
 
#58
  Alt 7. Jul 2004, 23:54
Zitat von neolithos:
Grund: Wenn du die Formel zu einer schnell durchrechenbaren Sprache umcompilierst und opimierst, vermute ich, dass das Teil schneller wird.
Die Sprache meines Parsers heisst "Baum"

Zitat von neolithos:
Bei Meinem Formel-Parser (der langsamer ist, durch Typenkonvertierungen und OOP) gehe ich wie folgt vor.
Ist meiner nicht OOP? Und hast du dir mal die ganzen Typecasts angesehen die ich da zwischen drin sitzen hab?

Zitat von neolithos:
(1 + sin(A))^3 * (1+1)

Erster Schritt:

zerlegen in Token (Teile):

"1" "+" "sin" "(" "A" ")" "^" "3" "*" "(" "1" "+" "1" ")"
Dies erledigt eine while Schleife gekoppelt mit einer Matrix.

Baue aus den Tokens einen Parsebaum:

Dazu wird ein vor definierter Syntax-Graph durchlaufen.
-> Wieder nur eine while-Schleife
Das mache ich z.B. in nur einer Rekursion (procedure TTF(...)). Die dort enthaltene irre große "if..then..else"-Verzweigung legt in ihrer Struktur und Reihenfolge den "virtuellen" Sytaxgraphen fest, und das Ende dieser einen Rekursion die sich direkt den zu parsenden String vornimmt ist der (fast) fertige Baum.

Zitat von neolithos:
Optimiere den Code:
in dem Fall wird 1+1 zusammengefasst.
Deswegen oben das "fast" in Klammern: Das mache ich in 2 rekursiven Schritten. Erst wird von den Blättern anfangend gekennzeichnet welche Knoten überhaupt "zusammenfassungswürdig" sind, also nicht Variablen oder von solchen abhängig sind. Im 2. Durchlauf findet die eigentliche Optimierung statt, die alles was möglich ist zusammen fasst.
(Diese Funktion ist in dem hier eingestellten glaub ich noch nicht vorhanden. Bei mir aber sehr wohl )

Zitat von neolithos:
Erzeuge Code:

Code:
push 1
push a
sin
and
push 3
power
push 2
mul
Und die Ausführung dieses Code's könnte man extrem Optimieren.
Array für Stack.
Sprung-Tabelle für Proceduren.
Und genau das spare ich mir. Dafür müsste man den Baum ein mal rekursiv durchlaufen um den Stack zu bilden, und dann muss man noch mal ran und den Stack lösen. Ich löse direkt den Baum, so dass diese rekursive Funktion als Rückgabewert das fertige Ergebnis liefert.

Ich hatte mal testweise 2 verschiedene Stackprinzipe eingebaut: Ein mal mit nur einem Stack, und mal mit getrennten Operanden- Werte- und Ergebnisstack.
Beide Versuche führten zu einer erheblichen Verlangsamung. (Man muss hierbei beachten, dass die Stärke meines Parsers ist, ein und die selbe, ein einziges Mal geparste Formel, immer und immer wieder zu lösen, mit veränderten Variablen. Also zum Plotten von Funktionen gut geeignet, oder halt für Fraktalrechnungen )
Bei der Variante mit einem Stack war das Problem, dass ich für jedes Mal Lösen den gesamten Stack "echt" kopieren musste. Und das hat einfach viel zu lange gedauert.
Bei der Variante mit 3 Stacks fiel der Kopieraufwand weg, aber der Overhead durch die Stackverwaltung in Form von Unterscheidung von Unären und Binären Operatoren, und der Indexverwaltung an sich, war wohl größer als der Overhead einer Rekursion. Zumindest hatten das meine Messungen ergeben.
Von daher bin ich beim Baum geblieben.

Was auch noch mit reinspielt ist, dass ich gerne die 3 Zahlentypen strukturell möglichst gleich abhandeln wollte. Und die Rechnerei mit komplexen Zahlen/Quaternionen gestaltet sich ja noch etwas anders als mit double, da man ja nicht die normalen Operatoren verwenden kann.
Weiteres Schmankerl ist in dieser Hinsicht auch das Variablenhandling. Es gibt 8 Variablen, denen es völlig egal ist ob sie nun ein double-Wert sind, ne komplexe Zahl, oder was auch immer. Daher bleibt die "usability" für den "Endbenutzer" (also Programmierer...) gut. Um mit dem Teil etwas mit double-Werten zu rechnen reicht folgendes:
Delphi-Quellcode:
var p: TCQParser;
    ergebnis: double;
.
.
p := TCQParser.Create;
p.Parse('(1 + sin(A))^3 * (1+1)');
p.SetVariable(A, pi);
p.Solve(ergebnis);
Naja, und ich bin (noch *g*) der Meinung dass ich meine beiden obersten Ziele (Speeeed und einfache Bedienbarkeit) einigermaßen gut erreicht habe.
Wenn du es aber hinbekommen solltest das Dingen noch schneller zu machen, dann bin ich der erste dem die Kinnlade runterfällt *provozier* .

Ich werde die Tage (in 1-2 Wochen) die neue Version posten. Ich will ein Parser-Battle


guts Nächtle,
dizzy
Fabian K.
  Mit Zitat antworten Zitat
neolithos

 
Delphi 7 Architect
 
#59
  Alt 8. Jul 2004, 00:50
Erstens:

Die Klammern hatte ich vergessen!

Zweitens:

Meinen Parser habe ich mit C# geschrieben und dort verwende ich verdammt viel in/outboxing. Dies scheint zu lasten der Performance gehen.

Drittens:

Jetzt hast du mich doch neugirig gemacht! Ich will mal wissen wie schnell in einem Win32-Programm ist. Wenn ich mal Zeit habe schreib ich das Teil um.

Viertens:

Meinem Parser werde ich aber nur Integer und Double beibringen.
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

 
Delphi 7 Enterprise
 
#60
  Alt 8. Jul 2004, 01:00
Zitat von neolithos:
Meinen Parser habe ich mit C# geschrieben und dort verwende ich verdammt viel in/outboxing. Dies scheint zu lasten der Performance gehen.
Okay, da resignier ich... Ich hab weder Plan von C, noch von .NET
Das entbehrt latürnich nahezu jeder Vergleichbarkeit.

Zitat von neolithos:
Jetzt hast du mich doch neugirig gemacht! Ich will mal wissen wie schnell in einem Win32-Programm ist. Wenn ich mal Zeit habe schreib ich das Teil um.
Also meiner ist bei double rund 0.5 bis 0.65 mal so schnell wie eine Formel in Delphi direkt geschrieben. Mangels Vergleichsmöglichkeiten halte ich das einfach mal für ein recht passables Ergebnis
Leider bleibt mir natürlich die Optimierung durch .NET verwehrt

Zitat von neolithos:
Meinem Parser werde ich aber nur Integer und Double beibringen.
Feigling
Fabian K.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 6 von 11   « Erste     456 78     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:31 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz