AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Funktionsplotter

Ein Thema von furby · begonnen am 24. Sep 2006 · letzter Beitrag vom 24. Sep 2006
Antwort Antwort
Benutzerbild von furby
furby

Registriert seit: 15. Sep 2005
Ort: Braunschweig
37 Beiträge
 
Turbo Delphi für Win32
 
#1

Funktionsplotter

  Alt 24. Sep 2006, 14:49
Hallo alle zusammen...
Ich bin gerade dabei einen ziemlich umfangreichen funktionsplotter zu schreiben. Dafür habe ich jetzt einen Matheparser programmiert, der auch schon ziemlich gut funktioniert. Das Zeichnen von Funktionen geht auch wunderbar. Jedoch dauert mir das alles viel zu lange, da ich wenn ich zu einem x wert den y wert ausrechne, jedesmal wieder meine funktion (ein string) parse... Jetzt wollte ich fragen ob und wie ich das vielleicht anders machen könnte um das plotten von Funktionen zu optimieren. Denn eigentlich müsste es doch reichen den string nur 1 mal zu parsen. Ich habe nämlich schon viele plotter gesehen, die viel schneller zeichnen als meiner. Und an meinem Parser liegt die Geschwindigkeit nicht, da dieser eigentlich im Vergleich sehr schnell ist. Mein Plotter ist ürbigens im Anhang angehängt, damit man sich vielleicht mal ein Bild machen kann.

Hier aber erstmal meine Prozedur.

Delphi-Quellcode:
procedure ZeichneGraph(s:string;image:TImage);
const
  dx = 0.001;
var
  x,y : real;

  function f(x : real) : extended;
  begin
    result := ParsestringX(s, x); // Hier kommt mein parser zum Einsatz
  end;

begin
  if functions[arraycount - 1].visible then
  begin
    x := xmin;
    y := f(x);
    image.canvas.MoveTo(ut(x),vt(y));
    while x < xmax do
    begin
      y := f(x);
      if (y < ymax) and (y > ymin) and (not error.boo) then // Wenn der Wert darstellbar und kein Fehler
                                                            // z.b. 1/x u. x = 0
      begin
        image.canvas.Pen.color := functions[arraycount-1].farbe;
        image.canvas.LineTo(ut(x),vt(y));
        x := x+dx;
      end
      else
      begin
        x := x +dx;
        y := f(x);
        image.canvas.MoveTo(ut(x),vt(y));
      end;
    end;
  end;
end;
Angehängte Dateien
Dateityp: exe fabiansplotter_168.exe (540,5 KB, 49x aufgerufen)
Fabian K
  Mit Zitat antworten Zitat
Dax
(Gast)

n/a Beiträge
 
#2

Re: Funktionsplotter

  Alt 24. Sep 2006, 14:56
Ohne Parsercode kann ich dir da leider nicht helfen.

Aber: den Parser als Funktion zu implementieren ist Schwachfug Bastel dir eine Klasse außenrum, die die Formel einmal in einen Bytecode kompiliert. Dann musst du nachher nur noch die Parameter und den Bytecode in einen Interpreter werfen, dann wirds wieder.
  Mit Zitat antworten Zitat
Benutzerbild von furby
furby

Registriert seit: 15. Sep 2005
Ort: Braunschweig
37 Beiträge
 
Turbo Delphi für Win32
 
#3

Re: Funktionsplotter

  Alt 24. Sep 2006, 14:59
Zitat:
Aber: den Parser als Funktion zu implementieren ist Schwachfug Wink Bastel dir eine Klasse außenrum, die die Formel einmal in einen Bytecode kompiliert. Dann musst du nachher nur noch die Parameter und den Bytecode in einen Interpreter werfen, dann wirds wieder.
hehe tut mir leid... Aber ich kann mir darunter nichts vorstellen. Besser gesagt ich habe noch nie etwas dergleichen gemacht. Wäre nett wenn du mir das nochmal irgendwie für Neulinge näher erläutern könntest.
Fabian K
  Mit Zitat antworten Zitat
Dax
(Gast)

n/a Beiträge
 
#4

Re: Funktionsplotter

  Alt 24. Sep 2006, 15:12
Wenn du einen Parser schreibst, zerlegst du die reingeworfene Formel ja erst mal. Sagen wir, du willst "1 + 2.3" parsen. Dann würdest du das in drei Teile zerlegen: "1", "+" und "2.3". Da sich der Rechner darunter noch nicht vorstellen kann, musst du dem Rechner beibringen, was er sich darunter vorzustellen hat. Normalerweise macht man so etwas mit Opcodes. Du könntest einen Opcode für die Addition einführen, der zwei Parameter nimmt. Da man Matheparser oder Parser allgemein gerne als Stackmaschinen implementiert, nimmt sich der Opcode eben die zwei Parameter vom Stack.

Dazu musst du noch einen Schritt vorschalten: die Formel so umbasteln, das man sie sinnvoll auf einen Stack pushen kann; also: das der Rechner den Add-Opcode ohne Probleme anwenden kann. Da die Parameter des Opcodes vor der Operation auf dem Stack sein müssen, müsste dein Stack vor der Addition so aussehen:
Code:
1
2.3
Am weitesten unten bedeutet als erstes vom Stack geholt, wohlgemerkt

Der Additionsopcode schnappt sich die beiden (popt sie vom Stack), addiert sie und pusht das Ergebnis zurück. Der Stack sieht dann so aus:
Code:
3.3
Werden wir mal ein wenig komplizierter: "1 + 2 * 3"

Der Parser zerlegt das Ding wieder in Atome (Konstanten und Operatoren), die du am Ende in die sogenannte UPN(umgekehrte polnische Notation)-Form umwandeln kannst. Das läuft nach Operatorvorrang ab. Der *-Operator ist "wichtiger" als der +-Operator und darf daher zuerst an den Stack. Seine Parameter "2" und "3" müssen aber trotzdem auf dem Stack sein. Deshalb sieht dein Zahlenstack so aus:
Code:
1
2
3
Der *-Operator nimmt sich also die beiden letzten von Stack, multipliziert und schreibt zurück. Dann addiert der Add-Operator den Rest.

Sprich: es gibt nicht nur den Numeralstack für Konstanten, Variable und Ergebnisse, sondern auch einen Opstack mit den Operatoren. Der sähe im letzten Beispiel so aus:
Code:
+
*
Weiter unten bedeutet wieder: als erstes dran.

Die Urpsrungsform der Stacks kann man getrost als Bytecode des Parsers bezeichnen. Wenn du dir diesen Bytecode speicherst und den später nur noch durch die Auswertungsmethode des Parsers rennen lässt, ist der Performanceunterschied zu deinem jetzigen Parser gigantisch.

Wenn du dich nicht scheust, dir etwas anzusehen, was es schon gibt, und daraus zu lernen, dann sieh dir unbedingt denHier im Forum suchenCQParser und vielleicht noch den Hier im Forum suchenECQP oder sogar Hier im Forum suchenHAM an. Letzteres würde ich dir als Neuling allerdings nicht so ganz ans Herz legen, denn der ist schon wirklich komplizierter
  Mit Zitat antworten Zitat
Benutzerbild von jakobwenzel
jakobwenzel

Registriert seit: 31. Aug 2005
Ort: Ingelheim am Rhein
141 Beiträge
 
FreePascal / Lazarus
 
#5

Re: Funktionsplotter

  Alt 24. Sep 2006, 15:57
Ganz andere Methode:
Funktion in ne DLL einkompilieren und dann dynamisch linken.
Jakob Wenzel
"My store now sells Ninja Weapons!"
Comicverkäufer bei den Simpsons
  Mit Zitat antworten Zitat
Dax
(Gast)

n/a Beiträge
 
#6

Re: Funktionsplotter

  Alt 24. Sep 2006, 16:00
Zitat von jakobwenzel:
Ganz andere Methode:
Funktion in ne DLL einkompilieren und dann dynamisch linken.
Ginge. Aber dazu müsste man den Delphi-Compiler mitliefern (Lizenztechnisch nicht möglich), oder den FreePascal-Compiler.
  Mit Zitat antworten Zitat
Benutzerbild von furby
furby

Registriert seit: 15. Sep 2005
Ort: Braunschweig
37 Beiträge
 
Turbo Delphi für Win32
 
#7

Re: Funktionsplotter

  Alt 24. Sep 2006, 16:05
Ich bin gerade dabei den erstgenannten Parser zu studieren. . Dabei ist mir aber aufgefallen, dass dieser genaus funktioniert wie meiner. Nur dass Das Ergebnis nicht gleich ausgerechnet wird, wie du glaub ich versucht hast zu erklären. Ich werd mal versuchen meinen so umzubauen. Vllt krieg ichs ja hin
Fabian K
  Mit Zitat antworten Zitat
Antwort Antwort


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 04:47 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