![]() |
Re: Quadratische Gleichungen vollständig lösen
Erster Fehlerbericht: Bug zB für: a=1 b=0 c=1. Mit der beigepackten EEX: -> Meldung "p is a very small nummber" dann "ungültige Gleitkomma-Op", in der D6-IDE x1=NAN x2=NAN.
Die "kleines p"-Logik ist noch ziemlich daneben, denn nach Ausgabe "p is a very small nummber" wird sqrt(0-1) berechnet -> Crash. Erste Abhilfe für den Fall oben: Ersetze if (p>=0) and (p<sqrt(Math.MinDouble)) then durch if (p>0) and (p<sqrt(Math.MinDouble)) then Ich sehe nicht, warum überhaupt soviel Aufhebes für "kleines p" gemacht wird. Kritisch sind hier eigentlich "nur" die Diskriminantenberechnung (und Overunder/flow). Ein Kriterium, wann die Diskriminante mit erhöhter Genauigkeit berechnet werden muß, findet man zB bei W.Kahan, On the Cost of Floating-Point Computation Without Extra-Precise Arithmetic ![]() Gammatester |
Re: Quadratische Gleichungen vollständig lösen
Ein weiterer Bug und zwei Vorschläge:
Bug: a=1, b=1e140, c=1 ergibt X1= -2,14326739881213E123 X2= -1E140 a wird zwar erst richtig mit Vieta berechnet, dann aber im else-Zweig von 'p<0' überschrieben. Vorschlag 1: Das Demo-Programm ist so geändert, das nur einmal die Gleichung gelöst wird, und nicht 6! (in Worten sechsmal) bei komplexen Lösungen. Vorschlag 2: Der "Small p"-Zweig wurde entfernt, wenn er beigehalten werden soll (wofür keine Notwendigkeit besteht, für kleine negative p wird er zB ja auch nicht benutzt!), muß eine Fallunterscheidung Diskriminante <0 und >=0 eingebaut werden. Hier der vollständige Code.
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,Math, ComCtrls; type TForm1 = class(TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Button1: TButton; Label1: TLabel; Edit4: TEdit; Edit5: TEdit; Button2: TButton; RichEdit1: TRichEdit; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} type MySolution = Record a,b,d:double; c:integer;// 1: 2 real solution; 2: 1 real solution; // 3: 2 complex solutions end; //Wolfgang Mix - Delphi-PRAXiS function SolveQuadraticEquation( a, b, c : Double ): MySolution; var p, q , discriminant, discriminant2, re, im: Double; begin // ax² + bx + c = 0 if (a = 0) then raise Exception.CreateFmt ('a should not be zero, no quadratic equation',[result.a]); p := b / a; q := c / a; //if p is a very big number - sqr(p/2) > MaxDouble if abs(p)>sqrt(Math.MaxDouble) then begin //code showmessage('p is a very big number'); //showmessage(floattostr(Math.MaxDouble)); result.a:=abs(p) + sqrt(0.25 - (q/p)/p); result.b:=abs(p) - sqrt(0.25 - (q/p)/p); result.c:=1; result.d:=0.25 - (q/p)/p; exit; end; // calculate discriminant discriminant := sqr(p/2) - q; Result.d := discriminant; // calculate real value re:=-p/2; // calculate imaginary value im:=sqrt(abs(discriminant)); //Form1.Edit7.Text:=FloatToStr(discriminant); if discriminant > 0 then begin // 2 solutions if p>=0 then begin Result.b := -p/2 - sqrt(discriminant); Result.a := q/Result.b; //x1 mit Vieta Result.c := 1; end else begin Result.a := -p/2 + sqrt( discriminant); Result.b := q/Result.a; //x2 mit Vieta Result.c := 1; end; end else if discriminant < 0 then begin // 2 complex solutions Result.a := re; Result.b := im; Result.c := 3; end else begin // 2 equal solutions Result.a := -p/2; Result.b := Result.a; Result.c := 2; end; end; procedure TForm1.Button1Click(Sender: TObject); var a,b,c,discriminant: double; indicator:integer; qs: MySolution; begin RichEdit1.Lines.Clear; a:=StrToFloat(Edit1.Text); b:=StrToFloat(Edit2.Text); c:=StrToFloat(Edit3.Text); if (a=0) then begin // Don't calculate showmessage ('a should not be zero, no quadratic equation'); sleep(2000); exit; end else begin {WE: Gleichung nur einmal lösen und Ergebnisse anzeigen} qs := SolveQuadraticEquation(a,b,c); indicator := qs.c; case indicator of 1: Begin Label1.Caption:='2 real solutions'; RichEdit1.Lines.Add ('X1= ' + FloatToStr(qs.a)); RichEdit1.Lines.Add ('X2= ' + FloatToStr(qs.b)); End; 2: Begin Label1.Caption:='1 real solution'; RichEdit1.Lines.Add ('X= ' + FloatToStr(qs.a)); end; 3: Begin Label1.Caption:='2 complex solutions'; RichEdit1.Lines.Add ('X1= ' + FloatToStr(qs.a)+ ' + ' + FloatToStr(qs.b)+ ' i '); RichEdit1.Lines.Add ('X2= ' + FloatToStr(qs.a)+ ' - ' + FloatToStr(qs.b )+ ' i '); End; end; discriminant:= qs.d; Edit4.Text:=FloatToStr(discriminant); Edit5.Text:=IntToStr(indicator); end; end; procedure TForm1.Button2Click(Sender: TObject); begin close; end; procedure TForm1.FormCreate(Sender: TObject); begin RichEdit1.Clear; end; end. |
Re: Quadratische Gleichungen vollständig lösen
@gammatester:
Vielen Dank, werde ich so übernehmen. Liebe Grüße Wolfgang [edit]... und bug bei sehr großen Zahlen beseitigt [/Edit]
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,Math, ComCtrls; type TForm1 = class(TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Button1: TButton; Label1: TLabel; Edit4: TEdit; Edit5: TEdit; Button2: TButton; RichEdit1: TRichEdit; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} type MySolution = Record a,b,d:double; c:integer;// 1: 2 real solution; 2: 1 real solution; // 3: 2 complex solutions end; //Wolfgang Mix - Delphi-PRAXiS function SolveQuadraticEquation( a, b, c : Double ): MySolution; var p, q , discriminant, discriminant2, re, im: Double; begin // ax² + bx + c = 0 if (a = 0) then raise Exception.CreateFmt ('a should not be zero, no quadratic equation',[result.a]); p := b / a; q := c / a; //if p is a very big number - sqr(p/2) > MaxDouble if abs(p)>sqrt(Math.MaxDouble) then begin showmessage('p is a very big number'); result.d := 0.25 - (q/p)/p; im := abs(p)*sqrt(abs(result.d)); if result.d>0 then begin result.a := -p/2 - sign(p)*im; result.b := q/result.a; result.c := 1; end else if result.d<0 then begin Result.a := -p/2; Result.b := im; Result.c := 3; end else begin Result.a := -p/2; Result.b := Result.a; Result.c := 2; end; exit; end; // calculate discriminant discriminant := sqr(p/2) - q; Result.d := discriminant; // calculate real value re:=-p/2; // calculate imaginary value im:=sqrt(abs(discriminant)); //Form1.Edit7.Text:=FloatToStr(discriminant); if discriminant > 0 then begin // 2 solutions if p>=0 then begin Result.b := -p/2 - sqrt(discriminant); Result.a := q/Result.b; //x1 mit Vieta Result.c := 1; end else begin Result.a := -p/2 + sqrt( discriminant); Result.b := q/Result.a; //x2 mit Vieta Result.c := 1; end; end else if discriminant < 0 then begin // 2 complex solutions Result.a := re; Result.b := im; Result.c := 3; end else begin // 2 equal solutions Result.a := -p/2; Result.b := Result.a; Result.c := 2; end; end; procedure TForm1.Button1Click(Sender: TObject); var a,b,c,discriminant: double; indicator:integer; qs: MySolution; begin RichEdit1.Lines.Clear; a:=StrToFloat(Edit1.Text); b:=StrToFloat(Edit2.Text); c:=StrToFloat(Edit3.Text); if (a=0) then begin // Don't calculate showmessage ('a should not be zero, no quadratic equation'); sleep(2000); exit; end else begin {WE: Gleichung nur einmal lösen und Ergebnisse anzeigen} qs := SolveQuadraticEquation(a,b,c); indicator := qs.c; case indicator of 1: Begin Label1.Caption:='2 real solutions'; RichEdit1.Lines.Add ('X1= ' + FloatToStr(qs.a)); RichEdit1.Lines.Add ('X2= ' + FloatToStr(qs.b)); End; 2: Begin Label1.Caption:='1 real solution'; RichEdit1.Lines.Add ('X= ' + FloatToStr(qs.a)); end; 3: Begin Label1.Caption:='2 complex solutions'; RichEdit1.Lines.Add ('X1= ' + FloatToStr(qs.a)+ ' + ' + FloatToStr(qs.b)+ ' i '); RichEdit1.Lines.Add ('X2= ' + FloatToStr(qs.a)+ ' - ' + FloatToStr(qs.b )+ ' i '); End; end; discriminant:= qs.d; Edit4.Text:=FloatToStr(discriminant); Edit5.Text:=IntToStr(indicator); end; end; procedure TForm1.Button2Click(Sender: TObject); begin close; end; procedure TForm1.FormCreate(Sender: TObject); begin RichEdit1.Clear; end; end. |
Re: Quadratische Gleichungen vollständig lösen
Ich würde mir wünschen, wen der Code einige Grundregeln sauberer Programmierung umsetzen würde:
1. Bezeichner sind nicht selbsterklärend. ('Im', 'Re', Feldbezeichner '.indicator', '.a'). Die Parameter a,b,c sind ok, denn das ist einschlägig bekannt. 2. Code-Styleguides werden ignoriert (Typen fangen z.B. in Delphi mit 'T' an) 3. Magic Numbers (case indicator of) 4. DRY-Prinzip ignoriert (mehrfache Verwendung fast identischer Faktoren/Formeln). 5. Verwendung englischer Bezeichner in einem deutschne Beispielcode. 5. Verwendung englischer Kommentare in einem deutschen Beispielcode. Weiterhin habe ich als Laie nicht begriffen, wo die Vorteile dieser sehr komplexen Lösung sind. Ich hätte gern ein paar numerische Beispiele, um die Vorteile zu erkennen. Ich kann mir das PDF ja durchlesen, aber einige Beispielrechnungen, anhand derer man die Klimmzüge nachvollziehen kann, wären für ein Tutorial und das Verständnis sehr hilfreich. Als Laie kann ich mir nämlich vorstellen, das das Problem der ziemlich großen Zahlen durch verwendung eines Extended-Zwischenresultats vermieden werden könnte (ich liege das sicherlich falsch, aber bis zur Behauptung des Gegenteils...). Hier der naive Vorschlag mit dem Versuch 1-5 zu vermeiden. Der Code sollte selbsterklärend sein (ist aber ungetestet):
Delphi-Quellcode:
Wenn man den numerisch sicherlich stabileren Code von Wolfgang hinsichtlich der Nomenklatur anpasst, könnte man beide Verfahren nehmen, um anhand von Beispielen die Überlegenheit des hier vorgestellten Codes zu verdeutlichen.
Type
TQuadratischeGleichungLoesungstyp = (qlEineLoesung, qlZweiLoesungen, qlKomplexeLoesungen); TLoesungEinerQuadratischenGleichung = Record LoesungsTyp : TQuadratischeGleichungLoesungstyp; Loesung1, Loesung2 : Double; end; Function LoeseQuadratischeGleichung (a,b,c : Double) : TLoesungEinerQuadratischenGleichung; Var basis, diskriminante, offset : Extended; begin If IsZero(a) Then Raise EDivByZero.Create('Es wurde ein ungültiger Parameter angegeben (a darf nicht null sein)'); basis := -b / (2*a); diskriminante := sqr(b) - 4*a*c; offset := sqrt(abs(diskriminante)) / (2*a); if diskriminante<0 then begin result.LoesungsTyp := qlKomplexeLoesungen; result.Loesung1 := basis; result.Loesung2 := offset; end else if diskriminante>0 then begin result.LoesungsTyp := qlZweiLoesungen; result.Loesung1 := basis - offset; result.Loesung2 := basis + offset; end else begin result.LoesungsTyp := qlEineLoesung; result.Loesung1 := basis; result.Loesung2 := result.Loesung1; end; end; Das wäre dann ein Paradebeispiel für mathematisch exakte Programmierung, und das sie nicht trivial ist. [edit]'determinante' durch 'diskriminante' ersetzt, dank W.Mix[/edit] |
Re: Quadratische Gleichungen vollständig lösen
@alzaimar: Mit Deinem Vorschlag wären wir wieder am Asugangspunkt. Zwar verständlicher und hübscher, aber keinen Deut besser. Wenn nur die pq-Formel gut umgesetzt werden soll in mathematisch exakte Programmierung, trifft jfheins' Argument aus #19 wieder zu. Ich meine, daß ein Codelib-Beitrag doch mehr bringen sollte.
Dein Vorschlag ignoriert sämtliche angesprochen numerischen Probleme. Selbst der Hinweis auf extended zieht nicht, da die Diskriminante (nicht Determinante!) sqr(b) - 4*a*c eh schon extended gerechnet und dann in double gespeichert wird. Auch tragen die von Dir gewählten Bezeichnungen Basis und Offset nicht zum Verständnis bei und sorgen eher für Verwirrung denn Klarheit. Nix für ungut Gammatester |
Re: Quadratische Gleichungen vollständig lösen
Ich persönlich finde es übrigens eher unpraktisch, dass das Ergebnis "kodiert" ist (man muss also den Lösungstypen auswerten und eine case-Unterscheidung machen, um überhaupt etwas mit dem Ergebnis anfangen zu können ...)
Schöner wäre es, stattdessen 2 kurze Funktionen bereitzustellen: Zum Beispiel eine Funktion die immer 2 komplexwertige Nullstellen liefert und eine andere (für die, die keine komplexen Zahlen mögen/brauchen) die 2 double-Werte zurückliefert, von denen dann einer oder beide NaN sein können (falls es nur eine oder keine reelle Nullstelle gibt) |
Re: Quadratische Gleichungen vollständig lösen
@alzaimar
Zuerst einmal: Ich betrachte mich nicht als Profiinformatiker sondern als vorangeschrittener Anfänger, zu mindestens in Delphi, mit dem ich mich erst 1 Jahr versuche. Die wissenschaftliche Weltsprache ist nun einmal Englisch. Folgt man Deinem Vorschlag, sollte dann konsequenterweise auch die gesamte Pascalsyntax eingedeutscht werden Ich versuche, mich weitgehend an das Styleguide von Embarcadero zu halten. Selbst das von Delhi-Treff nach deutsch übersetzte Styleguide verwendet englische Kommentare und Bezeichner. ![]() Ein weiterer Grund für mich, diesen Stil beizubehalten ist, daß hier nicht nur deutsches Publkum liest. @gammatester Danke für das hervorragende Scriptum von Prof. W. Kahan, das ich mir nebenbei auch noch zu Gemüte führen werde. Leider habe ich kein Mathlab, wäre deswegen aber dankbar für zu prüfende Koeffitienten a,b und c mit demonstrativ ungenauen und genaueren Ergebnissen. @jfheins: Im späteren Script werde ich schrittweise mit noch mehr Erklärungen an diesen Brocken heranführen und Deinen Vorschlag mit übernehmen. Ich merke langsam, das Tutorial wird zeitaufwendiger als ich dachte, macht aber nix :) |
Re: Quadratische Gleichungen vollständig lösen
Zitat:
Mit a=10^n, b=-2*10^n+2, c=10^n+2, also zB a=1000, b=-2002, c=1002. Mit den Deinen Bezeichnungen sind die Lösungen X1=1, X2=1+2/10^n und die Diskriminante D=1/10^(2n), und dies sind die Rechenergebnisse (erste Spalte ist n):
Code:
Sie zeigen auch schön, daß die Berechnung der Diskriminante der kritische Teil ist (mit der nicht gekürzten Formal ist sie immer b^2-4ac = 4!), und daß der Fehler in den Lösungen langsam nach "vorn kriecht" und ab n=8 reicht die genauigkeit nicht mehr aus.
1 X1=1,2 X2=0,999999999999999 D=0,0100000000000002
2 X1=1,02 X2=1 D=0,0001 3 X1=1,00199999999989 X2=1,00000000000011 D=9,99999999777763E-7 4 X1=1,0002 X2=1 D=1,0000000000049E-8 5 X1=1,0000200000111 X2=0,999999999988896 D=1,00000222078706E-10 6 X1=1,00000199988897 X2=1,00000000011103 D=9,99777951399272E-13 7 X1=1,00000020110428 X2=0,999999998895723 D=1,02220749226278E-14 8 X1=1,00000001 + 1,10490345560989E-8 i X2=1,00000001 - 1,10490345560989E-8 i D=-1,22081164621868E-16 Ich meine, daß im Rahmen der Delphi-Praxis und als Basis für ein Tutorial Deine jetzige Berechnungsroutine ausreicht. Wie schon von anderen gesagt, finde ich allerdings auch mM das Interface (also die Parameterübergabe) verbesserungswürdig. In dem von Dir angehängten PDF wird zB vorgegeben:
Delphi-Quellcode:
Ich verwende in meiner QuadSolv-Unit folgende Funktionen:
procedure SolveQuadraticEquation(var Anzahl: integer; var IstKomplex: boolean; var x1,x2: double);
Delphi-Quellcode:
function squad(a,b,c: double; var x1,y1,x2,y2: double): integer;
{-Solve the quadratic equation a*x^2 + b*x + c = 0. Result is the number} { of different solutions: 0 (if a=b=0), 1 (x1), or 2 (x1,x2). If the} { result is = -2, x1+i*y1 and x2+i*y2 are the two complex solutions.} { No precautions against over/underflow, NAN/INF coefficients return 0.} function squadx(a,b,c: double; var x1,y1,x2,y2: double): integer; {-Solve the quadratic equation a*x^2 + b*x + c = 0. Result is the number} { of different solutions: 0 (if a=b=0 or INF/NAN), 1 (x1), or 2 (x1,x2).} { If the result is = -2, then x1 + i*y1 and x2 + i*y2 are the two complex} { solutions. Uses scaling by powers of two to minimize over/underflows.} function squad_selftest: integer; {-Selftest for squad core routine, result=0 if OK, else number of the} { failing test case.} |
Re: Quadratische Gleichungen vollständig lösen
@gammatester:
Danke für die Test-Formel, die ist okay, aber wie kommt man auf sowas :?: Zitat:
|
Re: Quadratische Gleichungen vollständig lösen
Zitat:
Zitat:
Zitat:
![]() Zitat:
Ich dachte, es wird ein Tutorial und ein Tutorial würde in einer bestimmten Sprache geschrieben werden. Ich dächte, das wäre dann Deutsch. Das Tutorial würde sich an eher Mathematikinteressierte richten, und weniger an Softwareentwickler. Mir erscheint es nur konsequent, das deutsche Bezeichner und deutsche Kommentare in einem deutschen Tutorial für deutsche Mathematiker angebracht wären. Anders herum machst Du deinem Namen alle Ehre, wenn du die Sprachen Mix't :zwinker: Zitat:
Zitat:
Ich schrieb also als 'Laie', der einen 'naiven Gegenvorschlag' macht, und weiß, das er damit 'sicherlich falsch' liegt. Klonk? Man könnte meinen oder einen ähnlichen Code in das Tutoral einbringen, um anhand konkreter Beispiele zu zeigen, das die scheinbar triviale Lösung (von mir) ungenau ist. Mein Code sollte nur zeigen, das man es 'hübscher' hinbekommen kann. Zitat:
Es gibt übrigens im Context der 'sauberen Programmierung' bei der Ausformulierung von Formeln auch das Bestreben, diese ohne Zwischenresultate zu kodieren (wenn es denn verständlich ist). Dies könnte hier durchaus geschehen. Zitat:
|
Re: Quadratische Gleichungen vollständig lösen
@alzaimar:
Ich glaube, du hast meine Quelltexte nicht richtig gelesen. Die Variablen Re, Im und indicator sind direkt kommentiert. Für Kommentare und Bezeichner verwende ich die englische Sprache. Den Grund dafür habe ich gennant. Für mathematische Begriffe versuche ich, KORREKTE Bezeichner zu haben, also z.B. disccriminant anstelle von "Determinante", was etwas völlig anderes meint. Im Übrigen waren wir hier bereits an einem Punkt angelangt, Probleme von Auslöschung, Überlauf und Unterlauf zu erklären. Dazu finde ich in "Deinem" Code nichts. Was Lehrer betrifft würde ich mir wünschen, nur sachlich zu bleiben. Was das Tut betrifft: Das wird selbstverständlich deutsch. Gruß Wolfgang |
Re: Quadratische Gleichungen vollständig lösen
Variabeln kann man schon in englisch verfassen, die Kommentierung würde ich aber in der Sprache der Zielgruppe erfassen ( in diesem Fall deutsch) oder in chinesich, so dass auch wirklich keiner mehr etwas davon hat. :stupid:
|
Re: Quadratische Gleichungen vollständig lösen
ja gut, Ansichtssache, aber der Chinese und der Norweger hat mehr von englischer
Kommentierung. Dann muß Delphi-Treff sein verdeutschtes Styleguide von Embarcadero ändern. Aber egal, im TUT wirds sowieso komplett deutsch, und wenn gewünscht wird, die Kommentare zu verdeutschen, mache ich das. Ich würde jetzt aber lieber beim eigentlichen Thema bleiben oder abschließen. |
Re: Quadratische Gleichungen vollständig lösen
Zitat:
Zitat:
Zitat:
Schauen wir uns also deinen Code an: Wozu steht in deinem Code die 'Discriminant2'? Was meinst du damit? Was ist ein 'Re'? Webster sagt dazu "a rare heavy polyvalent metallic element", "an ancient hawk-headed Egyptian sun" oder gar "the syllable naming the second (supertonic) note of any major scale in solmization". Das "Im" ist gar nicht bekannt. Bitte definiere dein Verständnis von "KORREKTE Bezeichner". Zitat:
Erstmal ein Zitat aus meinem Beitrag: Zitat:
But as you prefer english, as english is a widely understood language and obviously the standard language of mathematicans, read this: I supplied a naive alternative (german: "naiven Gegenvorschlag") sample code to show how a clean code could be written. I also mentioned that the code would most likely fail (german: "sicherlich falsch"), as it was written by an amateur (german: 'Laie') and pointed out that the original code by Wolfgang is predominant. Verstehst Du das? Zitat:
Zitat:
Ich verstehe deine Borniertheit ehrlich gesagt nicht. Du bist ein sehr kompetenter Mathematiker, deine Ausführungen zu den quadratischen Gleichungen und die Erklärungen zu den Fallstricken finde ich sehr interessant, Du bereitest das Thema sehr gut auf. Top! Im Kodieren bist Du nicht so gut. Musst Du auch nicht. Dazu gibt es andere, die im Gegenzug mathematische Dorfdeppen sind, dafür aber wissen, wie man sauberen Code schreibt. Beides zusammen ergäbe ein wirklich brauchbares Tutorial. 60% bringen nichts. Weder dein Teil, weder die Beispiele und Anregungen vom gammatester, noch meine Anregung. Allerdings wäre ich (u.v.a.) in der Lage, mit deinen Ausführungen und den Beispielen vom gammatester sowohl eine saubere Implementierung hinzulegen, als auch eine Begründung zu verfassen, die inhaltlich korrekt wäre, indem ich mich von euch beiden belehren ließe. Du hingegen nicht. Das unterscheidet uns wohl. |
Re: Quadratische Gleichungen vollständig lösen
Zitat:
Hier geht es um Probleme, eine mathematisch relativ einfache Formel so zu implementieren, daß ohne Riesenaufwand für viele Fälle brauchbare Ergebnisse erzielt werden. Das war auch erreicht, bevor Du mit Deinem, wie Du selbst sagt, laienhaft und naiven Codevorschlag fast alles über Bord geworfen hast. Über Codierstil etc, Verwendung gemeinsamer Ausdrücke etc. kann man diskutieren. Ich habe minimal-invasive Vorschläge gemacht, und wenn Du den mathematisch-numerischen Teil im Kern gelassen und verbessert hättest, wäre es OK gewesen; ich denke, daß auch Wolfgang nichts dagegen hätte. Kommentare zu den anderen Polemiken, verkneife ich mir, da sie die Sache nicht voranbringen. |
Re: Quadratische Gleichungen vollständig lösen
Zitat:
Auch hier verkneife ich mir weitere Kommentare. |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
@gammatester: Nicht jeder hat Mathematik studiert. Und wer es hat, benötigt höchstwahrscheinlich dieses Tutorial nicht!
|
Re: Quadratische Gleichungen vollständig lösen
Zitat:
Man nehme die Doppelwurzel x1=x2=1, das gibt die quadratische Gleichung x^2 - 2x + 1 = 0, also a=1, b=-2, c=1. Jetzt wird x2 ein wenig gestört, also zB x2=1+e (e wie Epsilon). Das ergibt gibt dann a=1, b=-(2+e), c=1+e. Man kann für e jeden Wert einsetzen. Einen leicht sichtbare Effekt erhält man, wenn e = 1/10^n ist, oder was ich genommen habe e=2/10^n. Um schon Fehler in den Koeffizienten zu vermeiden, multipliziere man noch mit 10^n. |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Kommt Ihr bitte zum Thema zurück, oder ich werde versuchen,
mir gammatesater das Thema abzuschließen, wenn er dazu bereit ist |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Zitat:
|
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
@Wolfgang: Daniel, hat uns nicht darüber informiert, dass du zum Supermoderator ernannt wurdest.
Ja ich glaube du solltest das mit gammatester zusammen abchliessen, da du/ihr sowieso an keinen Anregungen anderen interessiert seid bzw. diese nicht euer Wissensniveau teilen. |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
:) Man müßte schon Grundlagen in Mathematik und Englisch beherrschen
|
Re: Quadratische Gleichungen vollständig lösen
Zitat:
Zitat:
Zitat:
Wenn das die deutschen Abkürzungen sind, was hat das dann in einem Code zu suchen, der vorgibt, englische Bezeichner zu verwenden? Übrigens gammatester, Zitat:
Als Friedensangebot ein Vorschlag, der hoffentlich alle Kritikpunkte eliminiert, und die Erfahrungen in einen lesbaren und kommentarlosen Code zu gießt, der englische Bezeichner verwendet. Ich find sie auch schöner, ich gebs ja zu. Über zu kurze, zu lange und korrekte Bezeichner lässt sich -wie immer- streiten. So weiss ich z.B. nicht, ob die Teilösung wirklich von Vieta ist (stand teilweise so im W.Mix-Code) und ob das mit den Diskriminanten immer stimmt.
Delphi-Quellcode:
Die Essenz ist die 'Solve'-Methode, die -denke ich- die Lösungsansätze von W.Mix und GT dokumentiert. Der Rest ist Mumpfe.
unit QuadraticEquationSolver;
interface uses SysUtils; type EInvalidAccessException = class(Exception); TQuadraticEquationSolutionType = (stUndefined, stReal, stSingle, stComplex); TQuadraticEquationSolver = class private FSolutionType: TQuadraticEquationSolutionType; FSolution2: Double; FDiscriminant: Double; FSolution1: Double; FRealPart: Double; FComplexPart: Double; procedure SetSingleSolution(solution: Double); procedure SetRealSolutions(solution1, solution2: Double); procedure SetComplexSolution(realPart, complexPart: Double); procedure SolveUsingVietaFormula(p, q: Double); procedure SolveUsingTransformedFormula(p, q: Double); function IsAPositiveAndVeryLargeNumber(n: Double): Boolean; function GetSolution1: Double; function GetSolution2: Double; function GetRealPartOfSolution: Double; function GetComplexPartOfSolution: Double; public constructor Create; procedure Solve(a, b, c: Double); property SolutionType: TQuadraticEquationSolutionType read FSolutionType; property Solution1: Double read GetSolution1; property Solution2: Double read GetSolution2; property RealPartOfComplexSolition: Double read GetRealPartOfSolution; property ComplexPartOfComplexsolution: Double read GetComplexPartOfSolution; end; implementation uses Math; { TQuadraticEquationSolver } {$Region 'Solving and Mathematics'} procedure TQuadraticEquationSolver.Solve(a, b, c: Double); var p,q : Double; begin Assert (Not IsZero(a), 'a must be nonzero'); p := b / a; q := c / a; if IsAPositiveAndVeryLargeNumber(p) then SolveUsingTransformedFormula(p, q) else begin FDiscriminant := sqr(p / 2) - q; case Sign(FDiscriminant) of +1: SolveUsingVietaFormula(p, q); 0 : SetSingleSolution(-p / 2); -1: SetComplexSolution(-p / 2, Sqrt(abs(FDiscriminant))); end; end end; procedure TQuadraticEquationSolver.SolveUsingVietaFormula(p, q: Double); var solution: Double; begin solution := -p / 2 - sign(p) * sqrt(FDiscriminant); SetRealSolutions(solution, q / solution); end; procedure TQuadraticEquationSolver.SolveUsingTransformedFormula(p, q: Double); var root: Double; begin FDiscriminant := (1 / 4 - (q / p) / p); root := sqrt(FDiscriminant); SetRealSolutions(abs(p) - root, Abs(p) + root); end; function TQuadraticEquationSolver.IsAPositiveAndVeryLargeNumber(n: Double): Boolean; begin Result := (abs(n) > sqrt(Math.MaxDouble)); end; {$EndRegion} {$Region 'Routines for setting the individual solutions'} procedure TQuadraticEquationSolver.SetComplexSolution(realPart, complexPart: Double); begin FSolutionType := stComplex; FRealPart := realPart; FComplexPart := complexPart; end; procedure TQuadraticEquationSolver.SetRealSolutions(solution1, solution2: Double); begin FSolutionType := stReal; FSolution1 := solution1; FSolution2 := solution2; end; procedure TQuadraticEquationSolver.SetSingleSolution(solution: Double); begin FSolutionType := stSingle; FSolution1 := solution; FSolution2 := solution; end; {$EndRegion} {$Region 'Property access'} function TQuadraticEquationSolver.GetSolution1: Double; begin if SolutionType = stComplex then raise EInvalidAccessException.Create('Access only if solution is not complex'); Result := FSolution1; end; function TQuadraticEquationSolver.GetSolution2: Double; begin if SolutionType = stComplex then raise EInvalidAccessException.Create('Access only if solution is not complex'); Result := FSolution2; end; function TQuadraticEquationSolver.GetRealPartOfSolution: Double; begin if SolutionType <> stComplex then raise EInvalidAccessException.Create('Access only if solution is complex'); Result := FRealPart; end; constructor TQuadraticEquationSolver.Create; begin FSolutionType := stUndefined; end; function TQuadraticEquationSolver.GetComplexPartOfSolution: Double; begin result := FComplexPart; end; {$EndRegion} end. Das Dilemma, das Lösung sowohl reale als auch komplexe Lösungen liefert, habe ich habe ich durch unterschiedliche Properties versucht, zu lösen. Reelle Lösungen (eine oder zwei) stehen in den Eigenschaften 'Solution1' und 'Solution2', die komplexen in 'RealPartOfComplexSolution' und 'ComplexPartOfComplexsolution'. Etwas lang, finde ich. Aber so fragt keiner nach. :zwinker: Bei 'Solution1' und 'Solution2' vielleicht schon... :gruebel: [edit]Seit wann werden Rechtschreibfehler vom DCC nicht erkannt? [/edit] [edit]Fehler beim Refaktorisieren dank gammatester beseitigt. [/edit] |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Code:
Wenn man das beseitigt hat, gibt's das nächste Problem. Wieviele Beispiele hast Du mit Deinem Code getestet? Mit a=1, b=-3, c=2. Gibt's erstmal 'nen Crash "a must be non-zero"! Da der Code ja selbst erklärend ist, fragt sich der geneigte User wieso ist a=1 zero?
[Error] QuadraticEquationSolver.pas(43): Invalid compiler directive: 'Region'
[Error] QuadraticEquationSolver.pas(89): Invalid compiler directive: 'EndRegion' [Error] QuadraticEquationSolver.pas(91): Invalid compiler directive: 'Region' [Error] QuadraticEquationSolver.pas(112): Invalid compiler directive: 'EndRegion' [Error] QuadraticEquationSolver.pas(114): Invalid compiler directive: 'Region' [Error] QuadraticEquationSolver.pas(145): Invalid compiler directive: 'EndRegion' [Fatal Error] Unit1.pas(23): Could not compile used unit 'QuadraticEquationSolver.pas' |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Ein hoch auf "lesbaren und kommentarlosen Code"! Wenn man den schlimmen Bug aus #64 beseitigt hat, kommt der "lesbaren und kommentarlosen Code" doch tatsächlich zu dem Ergebnis, das x^2 - 3x + 2 = 0 die Lösungen hat x1=3, x2=0.666666666666667!
Na denn gute Nacht! Gammatester Hinweis: die Lösungen sind x1=1 und x2=2. |
Re: Quadratische Gleichungen vollständig lösen
Zitat:
dafür nehme man qtoctave ![]() für kleine Aufgaben im Prinzip genau dasselbe wie matlab |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
gammatester, nu beruhig dich doch mal. Ich habe dich doch mit keiner Silbe angegriffen oder beleidigt oder sonstwas. Mir sind halt zwei blöde Fehler unterlaufen, die ich inzwischen im Code behoben habe. Danke übrigens für deine Hinweise. Über die Art und Weise kann man zwar geteilter Meinung sein, aber jeder hat eben sein eigenes Niveau.
|
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Hallo,
erst mal finde ich nicht schlecht wie ihr das Problem aufbereitet. Nur in einem Punkt muss ich alzaimar recht geben, wenn man für einem deutschen Forum ein Tut. schreibt sollten auch die Kommentare und Bezeichner deutsch sein, oder man schreibt alles auf Englisch. Der Norweger oder Chinese wird sich schon zu helfen wissen, wenn er in einem deutschen Forum unterwegs ist. Bis bald Chemiker |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
:roll:
Leute ... einige von Euch mögen brillante Mathematiker sein, andere brillante Codierer. Hier wird gekeilt um Begriffe und nun sogar um Compiler-Direktiven wie $REGION, die für das eigentliche Problem völlig irrelevant sind. Es wäre schön, wenn Ihr die Verhältnismäßigkeiten wiederherstellen könntet und so die Inhalte, die in diesem Thema bereits versammelt sind, zu einer ganzheitlichen Lösung zusammenführen könntet. Denn von allen beteiligten Fachrichtungen ist das Problem ja nun schon gelöst. |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Ich bin weder ein brillianter Mathematiker noch ein perfekter Codierer,
habe halt nur Spaß auf Algorithmen. Wenn man sich draußen ein bißchen abgekühlt hat und einen warmen Tee genießt, kommt man vielleicht zu folgender Erkenntnis: Das Problem dieses Themas ist, daß wir, in welcher Programmiersprache auch immer, nur einen kleinen begrenzten Zahlenbereich aus der Menge der reellen Zahlen haben, selbst beim Typ Extended und bei Berechnungen Rundungsfehler entstehen, der begrenzte Zahlenbereich unter/überschritten werden kann und Fehler durch Auslöschung entstehen können. Die Ausgangsformeln sind perfekt und welweit 1000-fach bewiesen. Ob man nun die eine oder andere Formel benutzt, ist völlig egal. Es gibt aber einige Mögtlichkeiten Fehler zu vermeiden, wenn man mit den wenigen Maschinenzahlen rechnet. Nicht mehr und nicht weniger soll mein Beitrag zeigen. Wenn man sich ein wenig bei den Unis umschaut, wird man auch nicht viel mehr dazu finden. Ich denke, vom Material her gesehen, haben wir jetzt genug, um alles nüchtern zusammen zu fassen. Gruß an alle Wolfgang |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Zum alzaimar-Code - ein Vorschlag und drei Bugs:
V: Wenn man schon für die einmalige Abfrage (abs(n) > sqrt(Math.MaxDouble)) eine eigene Funktion spendiert: IsAPositiveAndVeryLargeNumber sollte dann doch besser IsAVeryLargeNumber heißen, da ja abs(n) getestet wird. (Wieso eigentlich 'n'?) B1: Außerdem ist die sqrt(MaxDouble)-Logik noch nicht richtig implementiert. Mit s=sqrt(MaxDouble) hat x^2 +s + s^2 = 0, d.h. a=1, b=s, c=s^2, angeblich 2 relle Lösungen, leider allerdings beide =NAN in der IDE, Exception außerhalb. Tatsächlich gibt es, wie man leicht nachrechnet, zwei konjugiert komplexe Lösungen x1,x2 = 0.5*(1 +/- sqrt(3)*i)*s. B2: Weiter hat x^2 - 1e160*x + 0 = 0 angeblich die Lösungen x1=x2=1e160, richtig ist x=1e160, x2=0. B3: Und wiedermal das unsägliche iszero-Problem, das wir eigentlich schon ad acta gelegt hatten: Der Code weigert sich die Lösungen x1=1, x2=2 von (rx)^2 - 3r(r*x) + 2r^2 = 0 zu berechnen für abs(r) <= 1e-6. Noch eine Bemerkung zu Daniels "Compiler-Direktiven wie $REGION, die für das eigentliche Problem völlig irrelevant sind." In dem Codelib-Beitrag bitte bitte entfernen, da sie ja offensichtlich irrelevant sind, aber zumindest bis Delphi 10 das Kompilieren verhindern. Gruß Gammatester |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
[OT]
Herzlichen Glückwunsch dem "Threaderöffner" zum "runden" Geburtstag..alles Gute usw... geballt mit der Summe an Beiträgen (dato "777")..wenn das nichts ist !? :cheer: [/OT] |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
@Der.Kaktus:
[OT] Danke für die Glückwünsche [/OT] :) |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Liebe DPler,
die Diskussion im thread fand ich richtig gut und danke allen noch einmal für die rege Beteiligung. Inzwischen habe ich mir gedacht, das Tut auf das Wesentliche zu beschränken, nämlich auf die wesentlichen Probleme der Numerik, ohne Codebeispiele zu bevorzugen. Im thread gab es ja genügend gute Beispiele. Das nun gekürzte Tut habe ich Frederic am 02.02. zukommen lassen, damit er mit seinen Comoderatoren entscheiden kann, wo es untergebracht werden kann oder was man noch ändern sollte. Lassen wir Ihnen Zeit! Euch "normalen" Usern will ich den Entwurf aber nicht vorenthalten und hänge ihn an Post #1 an. Liebe Grüße Wolfgang |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Was hat dieses Tutorial eigentlich mit Delphi zu tun? Ich hab darin rein gar nichts entdeckt was mit Delphi zu tun hat und somit in die Codelib sollte (nach meiner persönlichen Meinung) :gruebel:
Anders ausgedrückt: Gehört so etwas nicht in eine Mathematikforum? Und dort wäre es vermutlich zu simpel um das sich jemand der Sache annimmt. Ich dachte immer in die Codelib sollen wichtige Dinge die ein Jeder gebrauchen kann und nicht gaaaanz viele gaaaanz spezielle Dinge die nur ein einziger in 20 Jahren einmal benötigt :? Dies ist meine ganz persönliche Meinung und ist somit nicht automatisch die Meinung des gesamten Teams |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Hi!
Es soll ja gar nicht mehr in die Codelib ;) Es ist als Tutorial gedacht (also auch dann später in die Sparte) und behandelt ein Problem, dass afair nur bei Computer-Berechnung auftritt und somit in einem Mathematik-Forum eher nicht passt, aber bei allen Programmiersprachen quasi auftritt. Insofern ist es doch ein Tutorial für allgemeines Programmieren, oder? Grüße, Frederic P.S. Auch nur persönliche Meinung ;) |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Ich denke, es paßt in beide Sparten, wenn man den Thread bestehen läßt,
meine Meinung. Im Tut gibt es ja einen Link auf diesen Thread. |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Zitat:
|
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Ich lasse einfach das Team entscheiden, und gut ist es.
Die Mods können ja dann die persönlichen Dinge und Polemiken aus dem Thread herausnehmen. Gruß Wolfgang |
Re: [Tutorial] Quadratische Gleichungen vollständig lösen
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:10 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz