Autor |
Beitrag |
cerebrum
Hält's aus hier
Beiträge: 10
|
Verfasst: Sa 28.09.02 18:37
Hallo!
Wie kann ich bei Angabe einer Funktionsvorschrfit (z.B. f(x)=x^2) diesen Graphen auf einem Canvas darstellen? 
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Sa 28.09.02 19:52
Wie du's auf Kästchenpapier auch machen würdest. Du legst einen Pixel in der horizontalen als 0-Wert fest. Dann gibst du der Funktion die x-Werte (also horizontale Pixel, gehend von 0) als Parameter und mit dem Rückgabewert gehst du bei den Pixeln in die Höhe. Allerdings wird dann der Graph bei Werten unter 100 ein bisschen klein... Man müsste dann evtl 10 Pixel für 1 setzen und die Funktion mit Dezimalzahlen rechnen, also 0,1; 0,2 usw, damit man auch die Werte zwischen diesen 10 Pixeln erfasst.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
cerebrum 
Hält's aus hier
Beiträge: 10
|
Verfasst: Sa 28.09.02 20:22
Also habe ich dann in einer Variablen die Funktion stehen und ersetze x immer durch einen höheren Wert. Aber wie kann ich dann den Ausdruck in der Variablen so ausführen lassen, dass er einen Wert zurückliefert???
|
|
MathiasH
      
Beiträge: 699
WinXP, Win98SE, Debian, Win95
D5 Stand, D6 Prof
|
Verfasst: So 29.09.02 11:46
dafür brauchst du nen Parser, der die Funktion analysiert und dann berechnet, ist verdammt schwer zu bauen  such mal nach "(Math)Parser"
MathiasH
_________________ "Viel von sich reden, kann auch ein Mittel sein, sich zu verbergen."
Friedrich Nietzsche
|
|
mazias
      
Beiträge: 19
|
Verfasst: Mo 30.09.02 16:15
...so einen Parser zu bauen ist gar nicht mal so schwer:
Man kann jede Gleichung so zerlegen das immer zwei Operanden alleine stehen, z.B: a*b*c*d = a*(b*(c*d))). Jetzt braucht man ne Rekursive Funktion die sich immer selbst aufruft wenn ne klammer kommt. Das ist im Prinzip schon alles, beim Zerlegen der Gleichung noch auf Punkt vor Strichrechnung achten und das ist dann das Wesentliche.
-Matze
|
|
MathiasH
      
Beiträge: 699
WinXP, Win98SE, Debian, Win95
D5 Stand, D6 Prof
|
Verfasst: Mo 30.09.02 19:19
naja eine funktion besteht aus mehr als *+-/() !!!!!
MathiasH
_________________ "Viel von sich reden, kann auch ein Mittel sein, sich zu verbergen."
Friedrich Nietzsche
|
|
DeCodeGuru
      
Beiträge: 1333
Erhaltene Danke: 1
Arch Linux
Eclipse
|
Verfasst: Mo 30.09.02 20:25
Zitat: | naja eine funktion besteht aus mehr als *+-/() !!!!! |
Wo er recht hat, hat er recht  Außerdem muss man noch beachten, dass Punkt- vor Strich-Rechnung gilt -> Du musst auch auf die Reihenfolge achten, wie die einzelnen Schritte ausgeführt werden.
_________________ Viele Grüße
Jakob
|
|
mazias
      
Beiträge: 19
|
Verfasst: Mo 30.09.02 21:43
...also wenn ihrs mir nicht glaubt werd ich mal ein bisschen präziser:
Zuerst machen wir eine Liste mit allen gängigen Operanden, geordnet so das Punkt vor Strich kommt und Potenzen vor Punkt und Sinus und Cosinus usw...
Dann nehmen wir uns den Funktionsstring und durchsuchen ihn nach Operanden(natürlich zuerst die höherwertigen) und setzen unsere Klammern links und rechts, und dann das ganze nochmal bis immer max 2 Argumente links und rechts neben einem Operanden stehen [z.B: f*a*b^2+d/c = f*a*(b^2)+d/c = (f*a)*(b^2)+(d/c) = ((f*a)*(b^2))+(d/c).
Das dann auszurechnen ist kein Problem (rekursive Funktion)...
|
|
Addy
      
Beiträge: 43
|
Verfasst: Di 01.10.02 11:53
Die Technik, durch Klammer-Setzen eine Priorität der Operanden zu erzwingen, habe ich vor einiger Zeit auch schon probiert. Das Ergebnis: der Programmcode wurde sehr kompliziert und der Algorithmus fehleranfällig.
Anderer Vorschlag (ungetestet): der gesamte Term wird geparst und in seine Bestandteile zerlegt (ein Bestandteil ist z.B. ein Operand, eine Zahl oder eine Klammer), die in einem dynamischen Array vom Typ (symbolischer Name  ) TBestandteil gespeichert werden. Jedes Element vom Typ TBestandteil repräsentiert entweder eine Zahl, einen Operanden etc., aber immer nur einen Bestandteil. Der Term
5*(a-3.5)
wird in die Bestandteile
5
*
(
a
-
3.5
)
zerlegt. Nun werden zuerst die Klammern ausgerechnet (höchste Priorität). Da Klammern auch geschachtelt sein können, empfiehlt es sich, eine rekursive Funktion zu benutzen, die den Wert der Klammer zurückliefert. Dabei sollte der Gesamtterm 5*(a-3.5) als (5*(a-3.5)) betrachtet werden, damit für Klammern und Gesamtterm ein und dieselbe Funktion benutzt werden kann.
In diesem aktuellen Zwischenterm a-3.5 werden zuerst alle Variablen durch ihre Werte ersetzt (z.B. bei a=4: 4-3.5). Danach werden die Rechenzeichen ihrer Priorität nach gesucht (hier: das Minuszeichen) und ausgewertet: Die Bestandteile links und rechts des Operanden werden gemäß dem Operanden miteinander ... ääh ... operiert  und alle 3 Bestandteile werden durch einen ersetzt, nämlich dem Ergebnis der Operation (die Zahl, hier: 0.5). Wenn in der gesamten Klammer nur noch ein Bestandteil (eine Zahl) steht, wird die öffnende und die schließend Klammer aus dem Array gelöscht, so dass nur noch die Zahl vorhanden ist. Unser Bestandteil-Array sieht dann so aus:
5
*
0.5
Das wird dann wie oben beschrieben ausgewertet, bis wieder nur noch eine Zahl (2.5) dasteht: das Ergebnis  .
Ich glaube, das Prinzip ist klar. Es hört sich alles sehr aufwändig und kompliziert an, aber ich bin sicher, es ist es nicht.
Die Vorteile sind (u.a.):
- Nachdem der String in das Bestandteil-Array eingelesen wurde, muss man nie mehr an einem String rumfummeln, was die Geschwindigkeit erhöht, den Quellcode wesentlich verkürzt, vereinfacht und fehlersicherer macht. Dieser Vorteil ist auf keinen Fall zu verachten.
- Nachdem die Grundstruktur vorhanden ist, kann man mit minimalem Aufwand weitere Operatoren hinzufügen. Ebenfalls ein sehr wichtiger Vorteil.
|
|
mazias
      
Beiträge: 19
|
Verfasst: Di 01.10.02 18:29
hi,
ich hab mir grad 2 Std. freigenommen und mal meine Theorie in die Praxis umgesetzt. Insgesamt sind es grade mal 200 Zeilen, und es funktioniert perfekt.
Der Algorhytmus schafft z.B. so ne Formel: 7,126*x^1.3/( x*X+(7+ 3*(x-x^ (2*x ))/x))
da man hier leider nicht's hochladen kann, poste ich mal den ganzen Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, math;
type pcalcpart = ^tcalcpart; tcalcpart = record left, right: pcalcpart; op : integer; x, hasvalue : Boolean; value : extended; text : string; end;
TForm1 = class(TForm) Edit1: TEdit; Button1: TButton; Memo1: TMemo; TreeView1: TTreeView; Button2: TButton; Edit_x: TEdit; Label1: TLabel; Label2: TLabel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public compformel: pcalcpart; { Public declarations } end;
const ops: Array[1..5] of String = ('-', '+', '/', '*', '^');
var Form1: TForm1;
implementation
{$R *.dfm}
procedure display(text: string); begin form1.memo1.lines.add(text); end;
function createcalcpart(ptext: string = ''): pcalcpart; begin result := new(pcalcpart); with result^ do begin left := nil; right := nil; op := -1; x := false; hasvalue := false; text := ptext; end; // debug display(result.text); end;
procedure displaystructure(p: pcalcpart; node: ttreenode; treeview: ttreeview); begin node.Text := p.text; if p.left <> nil then displaystructure(p.left, treeview.Items.AddChild(node,''), treeview); if p.right <> nil then displaystructure(p.right, treeview.Items.AddChild(node,''), treeview); if p.x = true then node.Text := node.Text + 'X'; if p.hasvalue then node.Text := node.Text + floattostr(p.value); end;
procedure decode1(p: pcalcpart); var c, d : integer; depth: byte; newp : pcalcpart; begin depth := 0; if p.text = '' then exit; // gucken ob Operator vorhanden ist for d := low(ops) to high(ops) do begin c := 1; while c <= length(p.text) do begin // Klammern umgehen if p.text[c] = '(' then inc(depth); if p.text[c] = ')' then dec(depth); if depth > 0 then begin inc(c); continue; end; if depth < 0 then begin showmessage('Flasche Klammersetzung'); exit; end; // niederwertigsten Operator suchen if copy( p.text, c, length(ops[d]) ) = ops[d] then begin p.left := createcalcpart( copy(p.text, 1, c - 1) ); p.right := createcalcpart( copy(p.text, c + length(ops[d]), length(p.text) - c - length(ops[d]) + 1) ); decode1(p.left); decode1(p.right); p.text := ops[d]; // wir haben einen gefunden und sind hier fertig exit; end; inc(c); end; // Falsche Klammersetzung if depth <> 0 then begin showmessage('Flasche Klammersetzung'); exit; end; end; // wir haben keinen Operator gefunden, das kann folgende Gründe haben... // 1. Nur vorne und hinten eine Klammer, z.B.: '(x+y)' if (p.text[1] = '(')and(p.text[length(p.text)] = ')')then begin p.text := copy(p.text, 2, length(p.text) - 2); decode1(p); exit; end; // 2. Nur noch ein X da if p.text = 'X' then begin p.x := true; p.text := ''; exit; end; // 3. Nur noch ne Zahl da for c := 1 to length(p.text) do if not(p.text[c] in ['0'..'9', ',']) then break; if c = length(p.text) + 1 then begin // die Schleife ist durchgelaufen also ist es ne Zahl p.hasvalue := true; p.value := strtofloat(p.text); p.text := ''; exit; end; // 4. Fehler showmessage('Fehlerhafte Formel.'); end;
function calc(p: pcalcpart; x: extended): extended; var left, right: extended; begin if p.text <> '' then begin left := calc(p.left , x); right := calc(p.right, x); if p.text = '-' then result := left - right; if p.text = '+' then result := left + right; if p.text = '*' then result := left * right; if p.text = '/' then result := left / right; if p.text = '^' then result := power(left, right); end; if p.x then result := x; if p.hasvalue then result := p.value; // debug display(floattostr(result)); end;
procedure TForm1.Button1Click(Sender: TObject); var c: integer; s: string; begin s := edit1.Text; // Schritt 1 // spaces raus, punkt zu komma for c := length(s) downto 1 do if s[c] = ' ' then delete(s, c, 1) else if s[c] = '.' then s[c] := ','; s := uppercase(s); // Schritt 2 // Computergerecht zerlegen compformel := createcalcpart(s); decode1(compformel); displaystructure(compformel, treeview1.Items.add(nil, 'Formel'), treeview1); end;
procedure TForm1.Button2Click(Sender: TObject); var res: extended; begin display('----'); res := calc(compformel, strtofloat(edit_x.Text)); display('----------'); display( 'f(' + edit_x.text + ') = ' + floattostr( res )); end;
end. |
und hier die dfm
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81:
| object Form1: TForm1 Left = 281 Top = 127 Width = 702 Height = 342 Caption = 'Form1' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Label1: TLabel Left = 16 Top = 48 Width = 14 Height = 13 Caption = 'x =' end object Label2: TLabel Left = 16 Top = 16 Width = 23 Height = 13 Caption = 'f(x) =' end object Edit1: TEdit Left = 48 Top = 16 Width = 361 Height = 21 TabOrder = 0 Text = '7,126*x^1.3/( x*X+(7+ 3*(x-x^ (2*x ))/x))' end object Button1: TButton Left = 416 Top = 16 Width = 105 Height = 25 Caption = 'Build Compformel' TabOrder = 1 OnClick = Button1Click end object Memo1: TMemo Left = 8 Top = 88 Width = 681 Height = 209 Lines.Strings = ( 'vor dem berechnen erst auf "build compformel" clicken!') TabOrder = 2 end object TreeView1: TTreeView Left = 528 Top = 16 Width = 161 Height = 65 Indent = 19 TabOrder = 3 end object Button2: TButton Left = 416 Top = 48 Width = 105 Height = 25 Caption = 'Calc' TabOrder = 4 OnClick = Button2Click end object Edit_x: TEdit Left = 48 Top = 48 Width = 361 Height = 21 TabOrder = 5 Text = '3' end end |
probierts mal aus und sagt mir eure Meinung
tschö
-Matze
|
|
Addy
      
Beiträge: 43
|
Verfasst: Fr 04.10.02 14:20
Das scheint ungefähr das zu sein, was ich gesagt habe...
|
|
|