Entwickler-Ecke
Algorithmen, Optimierung und Assembler - float to bruch
F34r0fTh3D4rk - So 27.11.05 09:40
Titel: float to bruch
Ich schreibe gerade eine Funktion, um Fließkommazahlen in Brüche umzuwandeln, für meine unit UBruchrechnung, soweit hab ichs jetzt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.Button6Click(Sender: TObject); var Bruch: TBruch; nc, i: integer; flt: extended; str: string; begin flt := strtofloat(edit5.text); nc := 1; for i := 1 to length(inttostr(round(frac(flt)))) do nc := nc * 10; Bruch.Zaehler := round(flt * nc); Bruch.Nenner := nc;
Bruch := p_kuerzen(Bruch); Label1.Caption := inttostr(Bruch.Zaehler); Label2.Caption := inttostr(Bruch.Nenner); end; |
Ganz Perfekt ist es noch nicht, auch hab ich noch so die bedenken, wie ich das mit periodischen Zahlen mache, aber ich denke, selbst an dieser Funktion lässt sich schon ne Menge Verbessern, ich hoffe mal, dass strings nicht sein müssen.
Aus 6/7 macht er:
0,857142857142857
und daraus macht er wieder 9/10
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| function BruchToFloat(Bruch: TBruch): Extended; begin result := Bruch.Zaehler / Bruch.Nenner; end;
procedure TForm1.Button7Click(Sender: TObject); var Bruch: TBruch; begin Bruch.Zaehler := strtoint(edit1.text); Bruch.Nenner := strtoint(edit2.text); edit5.Text := floattostr(BruchToFloat(Bruch)); end; |
(warum eigentlich nur 15 nachkommastellen ?)
Die unit die man zum kürzen und für die Brüche braucht gibts hier:
http://www.delphi-library.de/viewtopic.php?p=313675
Danke schonmal ;) Das fertige Ergebnis kommt dann in die Unit rein.
Lannes - So 27.11.05 11:49
Titel: Re: float to bruch
Hallo,
F34r0fTh3D4rk hat folgendes geschrieben: |
| ...(warum eigentlich nur 15 nachkommastellen ?) |
FloatToStr berücksichtigt nur 15 Stellen, hier die Alternativen bis 18 Stellen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.Button7Click(Sender: TObject); var Bruch: TBruch; begin Bruch.Zaehler := strtoint(edit1.text); Bruch.Nenner := strtoint(edit2.text); edit5.Text := Format('%.18f',[BruchToFloat(Bruch)]); end; |
F34r0fTh3D4rk - So 27.11.05 12:03
dachte ich mir, nur muss ich diese funktion hier irgendwie mal anständig optimieren:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure TForm1.Button6Click(Sender: TObject); var Bruch: TBruch; nc, i: integer; flt: extended; str: string; begin flt := strtofloat(edit5.text); nc := 1; for i := 1 to length(inttostr(round(frac(flt)))) do nc := nc * 10; Bruch.Zaehler := round(flt * nc); Bruch.Nenner := nc;
Bruch := p_kuerzen(Bruch); Label1.Caption := inttostr(Bruch.Zaehler); Label2.Caption := inttostr(Bruch.Nenner); end; |
ich will möglichst die string umwandlungen und am besten noch frac da raus haben, nur wie ?
Aus 1,587 macht er 8/5 aus 8/5 aber 1,6
ohne runden stimmts jetzt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.Button6Click(Sender: TObject); var Bruch: TBruch; nc, i: integer; flt: extended; begin flt := strtofloat(edit5.text); nc := 1; for i := 1 to length(floattostr(frac(flt))) do nc := nc * 10; Bruch.Zaehler := round(flt * nc); Bruch.Nenner := nc;
Bruch := p_kuerzen(Bruch); Label1.Caption := inttostr(Bruch.Zaehler); Label2.Caption := inttostr(Bruch.Nenner); end; |
Fehler von mir, sry, nur muss man die nachkommastellen doch auch irgendwie anders herausbekommen, nur wie ?
F34r0fTh3D4rk - So 27.11.05 13:44
nochmal den relevanten teil als funktionen:
Delphi-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:
| type TBruch = record Zaehler, Nenner: integer; end;
function p_ggT(a, b: integer): integer; var x, y, r: Integer; begin x := a; y := b; r := x mod y; while (r <> 0) do begin x := y; y := r; r := x mod y; end; result := y; end;
function p_kuerzen(Bruch: TBruch): TBruch; var ggt: integer; begin result := Bruch; ggt := p_ggt(Bruch.Zaehler, Bruch.Nenner); if ggt = 1 then exit; result.Zaehler := Bruch.Zaehler div ggt; result.Nenner := Bruch.Nenner div ggt; end;
function BruchToFloat(Bruch: TBruch): Extended; begin result := Bruch.Zaehler / Bruch.Nenner; end;
function FloatToBruch(a: Extended): TBruch; var Faktor, i: integer; begin result.Nenner := 0; result.Zaehler := 0; Faktor := 1; for i := 1 to length(floattostr(frac(a))) do Faktor := Faktor * 10; result.Zaehler := round(a * Faktor); result.Nenner := Faktor; result := p_kuerzen(result); end; |
die markierten teile stören mich noch und die schleife müsste auch nicht unbedingt sein :?
ich könnte auch einfach maxint als faktor nehmen, aber das macht die funktion bissl langsam denke ich. hm geht ja net, dann übersteige ich maxint, so ein dreck, wenn ich dann aber int64 nehmen, bekomme ich so kein maximum :(
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| function FloatToBruch(a: Extended): TBruch; begin result.Nenner := 0; result.Zaehler := 0; result.Zaehler := round(a * 1000000000); result.Nenner := 1000000000; result := p_kuerzen(result); end; |
bei zahlen die ein wenig größer sind gibts dann probleme :( das muss doch irgendwie zu lösen sein :?:
BenBE - So 27.11.05 15:15
Zum zurückwandeln von Brüchen aus deren Dezimaldarstellung nimmt man meist die Kettenbruch-Zerlegung mit Hilfe des euklidischen Algos.
Delphi-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:
| I := 0; While Frac(X) > epsilon Do Begin K[I] := Trunc(X); X := 1 / Frac(X); Inc(I); end;
Z := Trunc(X); N := 1;
While I > 0 do Begin Tmp := N; N := Z; Z := Tmp;
Dec(I); N := N + K[I] * Z; end; |
Ungetestet ...
F34r0fTh3D4rk - So 27.11.05 15:35
ist das schneller, als eine umwandlung in einen string ?
was ist epsilon und muss der bruch danach noch gekürzt werden ?
DaRkFiRe - Mo 28.11.05 22:20
Epsilon ist eine Art Toleranzgrenze, die Du vorgibst.
BenBE - Mo 28.11.05 22:29
Je nach Wahl des Epsilons (Toleranzgrenze, normalerweise <1E-10) wirst Du eine Bruch-Annäherung machen müssen, d.h. dass er Dir den gekürzten Bruch
1000\3001 zurückgibt, obwohl Du 1/3 erwartest. Diese annäherung ist aber relativ einfach zu bewerkstelligen, da du einfach beim Zurückmultiplizieren nicht alle Glieder berücksichtigst.
F34r0fTh3D4rk - Di 29.11.05 13:07
dann ist es aber nicht so genau wie meins ;) und vielleicht auch langsamer :?
Horst_H - Di 29.11.05 13:56
Hallo,
auch die Umwandlung in einen String hat keine unendliche Genauigkeit und kostet auch gewaltig Zeit.
Wandel mal 3.14159265.. um.
Der Kettenbruch liefert schon frueh 355/113 auch ohne GGT-bestimmung
Gruss Horst
F34r0fTh3D4rk - Di 29.11.05 15:03
wie muss epsilon denn gewählt sein, um die richtigen brüche rauszubekommen ?
lässt sich die anzahl der nachkommastellen irgendwie anders bestimmen ?
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!