Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Extended in bruch umformen (https://www.delphipraxis.net/60923-extended-bruch-umformen.html)

glkgereon 14. Jan 2006 11:39


Extended in bruch umformen
 
Hi

Ich kann es ehrlich gesagt kaum glauben, das es zu diesem Thema noch keine wirkliche Lösung gibt...

das einzige was ich finden konnte war folgendes:

Delphi-Quellcode:
procedure DezToBruch(DezimalZahl:double;var Zaehler,Nenner:integer;Tiefe:integer);
const ZuKlein=1E-6;
      Winzig=1E-12;
var GanzAnteil,a,b:integer;
begin
   GanzAnteil:=trunc(DezimalZahl+Winzig);
   if (Tiefe>1) and (abs(DezimalZahl-GanzAnteil)>ZuKlein) then begin
      DezToBruch(1/(DezimalZahl-GanzAnteil),a,b,Tiefe-1);
      Zaehler:=a*GanzAnteil+b;
      Nenner:=a;
   end else begin
      Zaehler:=GanzAnteil;
      Nenner:=1;
   end;
end;
Von hier

Aber wenn man beispielsweise -0.1 reintut, kommt -1/9 raus :(

gibt es irgendwo eine komplett funktionierende Lösung?

negaH 14. Jan 2006 17:55

Re: Extended in bruch umformen
 
Das funktioniert auch nicht, zumindestens nicht ohne eine Library wie mein DECMath ;)

Verdeutliche dir doch mal folgendes

1 * 2^10000, als Extended benötigt man dafür eine 48 Bit große Manitsse die binär 1 einhält und als Exponenten einen maximal 15 Bit großen Wert der 10000 binär enthält. Nun wandele diese Zahl in einen Bruch um ! Es entsteht 1 * 2^10000 / 1 ergo eine Binärzahl aus einer führenden 1 mit 10000 Nullen dran. Diese große Zahl, eg. Bruch kann nur mit einer math. Library die solch großen Zahlen fassen kann dargestellt werden.

Und in fact, in meinem DECMath gibt den Datentyp IRational -> ergo rationale Brüche, die einen Extendend aufnehmen können und diesen dann intern als Bruch darstellen.

Delphi-Quellcode:
var
  R: IRational;
begin
  NSet(R, 1 / 3);
 
  WriteLn('R: ', NStr(R) );
  WriteLn('F: ', NFloat(R) );
  WriteLn('N: ', NStr(R.N) );
  WriteLn('D: ', NStr(R.D) );
end;

// ergibt als Ausgabe

R: 0,333333333333333333333333333333333333333333333333333333
F: 0,3333333

N: 1
D: 3
Intern wird der Extended sehr simpel umgewandelt.

Man extrahiert dazu die Mantisse als 48 Bit Binärzahl und den Exponenten zur Basis 2 ebenfalls als Binärzahl. Je nach Vorzeichen des Exponenten ist die Zahl kleiner 1.0 oder größer.

Delphi-Quellcode:
procedure NSet(var A: IRational; const B: Extended);
type
  ExtRec = packed record
    Man: array[0..1] of Cardinal;
    Exp: Word;
  end;
var
  I: Integer;
begin
  NSet(A, 0);
  if B <> 0 then
    with NAlloc(A)^ do
    begin
      if ExtRec(B).Exp and $7FFF = $7FFF then
      begin // B >= 1.0
        NSet(FN, B);
        NNormalize(A);
      end else
      begin // B < 1.0
        I := (ExtRec(B).Exp and $7FFF) - $3FFE - 64;
        NSet(FN, ExtRec(B).Man, 8);
        NNeg(FN, B < 0);
        if I > 0 then NShl(A, I) else
          if I < 0 then NShr(A, -I)
            else NNormalize(A);
      end;
    end;
end;
Entscheidend ist die sogenannte Normalization eines Bruches, d.h. aus 4/6 den kleinesten eindeutigen Bruch von 2/3 zu finden.

R = N//D
T = GCD(N, D)
R' = (N/T) // (D/T)

// Bruchstrich.

Wie man sieht muß man den größten gemeinsammen Teiler vom Nominator N und Denominator D per GCD() finden. Dieser Wert T wird dann 1 oder größer 1 sein.

Gruß hagen

glkgereon 14. Jan 2006 19:53

Re: Extended in bruch umformen
 
Hmm...irgendwo hatte ich diesen Teil der DEC mal gesehen bei mir auf der Platte....aber ich finde ihn nicht mehr :(

Gibt es eine neue Version für D2005 oder soll ich den aus dem Thread hier in der DP nehmen?


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:58 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