Einzelnen Beitrag anzeigen

Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#2

Re: Extended in bruch umformen

  Alt 14. Jan 2006, 18:55
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
  Mit Zitat antworten Zitat