Autor Beitrag
F34r0fTh3D4rk
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: So 27.11.05 10:40 
Ich schreibe gerade eine Funktion, um Fließkommazahlen in Brüche umzuwandeln, für meine unit UBruchrechnung, soweit hab ichs jetzt:
ausblenden 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);  //Die Float Variable
  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);  //Kuerzen

  //Ausgeben
  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

ausblenden 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:

www.delphi-library.d...ewtopic.php?p=313675

Danke schonmal ;) Das fertige Ergebnis kommt dann in die Unit rein.
Lannes
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2352
Erhaltene Danke: 4

Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
BeitragVerfasst: So 27.11.05 12:49 
Hallo,
user profile iconF34r0fTh3D4rk hat folgendes geschrieben:
...(warum eigentlich nur 15 nachkommastellen ?)

FloatToStr berücksichtigt nur 15 Stellen, hier die Alternativen bis 18 Stellen:
ausblenden 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 := FloatToStr(BruchToFloat(Bruch));
  edit5.Text := Format('%.18f',[BruchToFloat(Bruch)]);
  //oder
  //edit5.Text := FormatFloat('0.000000000000000000',BruchToFloat(Bruch));
  //edit5.Text := FloatToStrF(BruchToFloat(Bruch),ffFixed,18,18);
end;

_________________
MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: So 27.11.05 13:03 
dachte ich mir, nur muss ich diese funktion hier irgendwie mal anständig optimieren:
ausblenden 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);  //Die Float Variable  
  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);  //Kuerzen  
 
  //Ausgeben  
  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:
ausblenden 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);  //Die Float Variable
  //showmessage(floattostr(flt));
  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);  //Kuerzen

  //Ausgeben
  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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: So 27.11.05 14:44 
nochmal den relevanten teil als funktionen:
ausblenden volle Höhe 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 <> 0do
  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 :(
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
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 * 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 27.11.05 16:15 
Zum zurückwandeln von Brüchen aus deren Dezimaldarstellung nimmt man meist die Kettenbruch-Zerlegung mit Hilfe des euklidischen Algos.

ausblenden 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:
//Kettenbrucherzeugung
I := 0;
While Frac(X) > epsilon Do
Begin
    K[I] := Trunc(X);
    X := 1 / Frac(X);
    Inc(I);
end;

//Initialisierung des Bruchs
Z := Trunc(X);
N := 1;

//Rückumwandlung
While I > 0 do
Begin
    //Reziprokes bilden
    Tmp := N;
    N := Z;
    Z := Tmp;

    Dec(I);
    N := N + K[I] * Z;
end;


Ungetestet ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: So 27.11.05 16:35 
ist das schneller, als eine umwandlung in einen string ?
was ist epsilon und muss der bruch danach noch gekürzt werden ?
DaRkFiRe
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 526

WinXP Home & Professional
C, C++, Delphi
BeitragVerfasst: Mo 28.11.05 23:20 
Epsilon ist eine Art Toleranzgrenze, die Du vorgibst.

_________________
Lang ist der Weg durch Lehren - kurz und wirksam durch Beispiele! Seneca
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 28.11.05 23: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.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 29.11.05 14:07 
dann ist es aber nicht so genau wie meins ;) und vielleicht auch langsamer :?
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Di 29.11.05 14: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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 29.11.05 16:03 
wie muss epsilon denn gewählt sein, um die richtigen brüche rauszubekommen ?

lässt sich die anzahl der nachkommastellen irgendwie anders bestimmen ?