Page 1 of 2 1 2 LastLast
Results 1 to 15 of 17

Thread: TExtendedHelper.BuildUp()

  1. #1

    TExtendedHelper.BuildUp()

    Hallo,

    Ik loop weer tegen een mogelijke incompatibiliteit van fpc versus Delphi aan.

    Wat is in Delphi het resultaat van deze functie?

    Delphi Code:
    1. uses sysutils, math;
    2.  
    3. function TestExtendedBuildUp: Boolean;
    4. var
    5.   E1, E2: Extended;
    6.   ESign: Boolean;
    7.   EMant, EExp: QWord;
    8. begin
    9.   E1 := 1.0;
    10.   ESign := E1.Sign;
    11.   EMant := E1.Mantissa;
    12.   EExp := E1.Exp;
    13.   E2.BuildUp(ESign, EMant, EExp);
    14.   Result := SameValue(E1, E2);
    15. end;

    Uitgaande van de help tekst zou ik vermoeden dat het resultaat TRUE zou moeten zijn.
    Fpc geeft False (voor alle typen floats).

    Wil iemand dit testen, bij voorkeur op 32-bits (in 64-bit: extended=double), en daarbij ook vermelden met welke Delphi versie werd getest?

    Mijn dank is weer groot,

    Bart

  2. #2
    En een vervolgvraag.
    De mantissa heeft een impliciete begin-bit: 1, deze wordt weggelaten in in het formaat van Double en Single, maar niet bij Extended.
    Ik denk dat fpc dit impliciete bit niet meegeeft als je de mantissa opvraagt.
    Geen idee hoe Delphi dat doet.

    Wat is de output van het volgende programma onder Delphi (32-bit executable)?
    Delphi Code:
    1. program fl;
    2.  
    3. {$apptype console}
    4. {$ifdef fpc}
    5. {$mode objfpc}
    6. {$h+}
    7. {$endif}
    8.  
    9. uses
    10.   SysUtils, Math;
    11.  
    12. const
    13.   Signs: Array[Boolean] of Char = ('+','-');
    14.   Test = 1.999755859375;    //(8192-1)/4096
    15.  
    16.   function DbgS(E: Extended): String; overload;
    17.   begin
    18.     Result := 'Sign: ' + Signs[E.Sign] +
    19.               ', Mantissa: ' + IntToHex(E.Mantissa, SizeOf(E.Mantissa)*2) +
    20.               ', Exp: ' + IntToHex(E.Exp, SizeOf(E.Exp)*2) +
    21.               ', Frac: ' + IntToHex(E.Frac, SizeOf(E.Frac)*2);
    22.   end;
    23.  
    24. function DbgS(D: Double): String; overload;
    25. begin
    26.   Result := 'Sign: ' + Signs[D.Sign] +
    27.             ', Mantissa: ' + IntToHex(D.Mantissa, SizeOf(D.Mantissa)*2) +
    28.             ', Exp: ' + IntToHex(D.Exp, SizeOf(D.Exp)*2) +
    29.             ', Frac: ' + IntToHex(D.Frac, SizeOf(D.Frac)*2);
    30. end;
    31.  
    32. function DbgS(S: Single): String; overload;
    33. begin
    34.   Result := 'Sign: ' + Signs[S.Sign] +
    35.             ', Mantissa: ' + IntToHex(S.Mantissa, SizeOf(S.Mantissa)*2) +
    36.             ', Exp: ' + IntToHex(S.Exp, SizeOf(S.Exp)*2) +
    37.             ', Frac: ' + IntToHex(S.Frac, SizeOf(S.Frac)*2);
    38. end;
    39.  
    40.  
    41. procedure TestBreakDown;
    42. var
    43.   E: Extended;
    44.   S: Single;
    45.   D: Double;
    46. begin
    47.   E := Test;
    48.   writeln('E = ',E:20:20,#32,DbgS(E));
    49.   D := Test;
    50.   writeln('D = ',D:20:20,#32,DbgS(D));
    51.   S := Test;
    52.   writeln('S = ',S:20:20,#32,DbgS(S));
    53. end;
    54.  
    55. begin
    56.   TestBreakDown;
    57. end.

    FreePascal geeft:
    Code:
    E = 1.99975585937500000000 Sign: +, Mantissa: 7FF8000000000000, Exp: 0000000000003FFF, Frac: FFF8000000000000
    D = 1.99975585937500000000 Sign: +, Mantissa: 000FFF0000000000, Exp: 00000000000003FF, Frac: 001FFF0000000000
    S = 1.99975585900000000000 Sign: +, Mantissa: 00000000007FF800, Exp: 000000000000007F, Frac: 00000000087FF800
    Bart

  3. #3
    Delphi 10.2 Version 25.0.26309.314 32-bit
    Code:
    E = 1.99975585937500000000 Sign: +, Mantissa: FFF8000000000000, Exp: 0000000000003FFF, Frac: FFF8000000000000
    D = 1.99975585937500000000 Sign: +, Mantissa: 001FFF0000000000, Exp: 00000000000003FF, Frac: 000FFF0000000000
    S = 1.99975585937500000000 Sign: +, Mantissa: 0000000000FFF800, Exp: 000000000000007F, Frac: 00000000007FF800
    Delphi 10.2 Version 25.0.26309.314 64-bit
    Code:
    E = 1.99975585937500000000 Sign: +, Mantissa: 001FFF0000000000, Exp: 00000000000003FF, Frac: 000FFF0000000000
    D = 1.99975585937500000000 Sign: +, Mantissa: 001FFF0000000000, Exp: 00000000000003FF, Frac: 000FFF0000000000
    S = 1.99975585937500000000 Sign: +, Mantissa: 0000000000FFF800, Exp: 000000000000007F, Frac: 00000000007FF800

  4. #4
    Bedankt voor het testen.
    Heb je ook een antwoord op mijn eerste vraag?

    Bart

  5. #5
    Quote Originally Posted by Bart B View Post
    Heb je ook een antwoord op mijn eerste vraag?
    Voor allebei 32 bit en 64 bit is het resultaat False.
    (Ik moest wel van QWord een UInt64 maken want Delphi heeft geen QWord zover ik kan zien.

    In de debugger is bij 32 bit:
    ESign = False
    EMant = 9223372036854775808
    EExp = 16383
    E2 = 5,94865747678616e+4931 in 32 bit)

    en bij 64 bit:
    ESign = False
    EMant = 4503599627370496
    EExp = 1023
    E2 8,98846567431158e+307

    Overigens heeft Delphi 10.2 een define genaamd EXTENDEDHAS10BYTES.
    In 32 bit is de SizeOf(Extended) 10 en in 64 bit is het 8

    Zie ook http://docwiki.embarcadero.com/Libra...ystem.Extended

    Zijn Floating points niet van nature onnauwkeurig?
    Ik neem aan dat je dit artikel wel kent: http://rvelthuis.de/articles/articles-floats.html
    Was er ook nier een unit bignumbers.pas ofzoiets die met hele grote nummers kon werken?

    Ook van Rudy: http://www.rvelthuis.de/programs/bigdecimals.html
    Last edited by rvk; 16-Dec-17 at 22:40.

  6. #6
    Merkwaardig, wat doet BuildUp dan eigenlijk?

    > Zijn Floating points niet van nature onnauwkeurig?

    OK, onnauwkeurig, maar toch niet met een factor 10^4931?
    Overigens is SameValue nu juist bedacht vanwege die onnauwkerigheid.
    Testen op EenFloat = EenAndereFloat gaat vrijwel zeker mis.

    Bart

    PS. Je bekijkt het in de debugger, die geeft nog wel eens vreemde waardes als de variabele out of scope is?
    Krijge je dezelfde waarde als je een writeln('E2 = ',E2) doet?

  7. #7
    Quote Originally Posted by Bart B View Post
    Krijge je dezelfde waarde als je een writeln('E2 = ',E2) doet?
    Yep.
    Code:
    ESign = FALSE
    EMant = 9223372036854775808
    EExp = 16383
    E2 =  5.94865747678616E+4931
    FALSE
    Delphi Code:
    1. program Project11;
    2. {$APPTYPE CONSOLE}
    3. uses sysutils, math;
    4.  
    5. function TestExtendedBuildUp: Boolean;
    6. var
    7.   E1, E2: Extended;
    8.   ESign: Boolean;
    9.   EMant, EExp: UInt64;
    10. begin
    11.   E1 := 1.0;
    12.   ESign := E1.Sign;
    13.   EMant := E1.Mantissa;
    14.   EExp := E1.Exp;
    15.   E2.BuildUp(ESign, EMant, EExp);
    16.   Result := SameValue(E1, E2);
    17.   Writeln('ESign = ', ESign);
    18.   Writeln('EMant = ', EMant);
    19.   Writeln('EExp = ', EExp);
    20.   Writeln('E2 = ', E2);
    21. end;
    22.  
    23. begin
    24.   Write(TestExtendedBuildUp);
    25.   Readln;
    26. end.

  8. #8
    Overigens fiept Lazarus trunk er bij mij op SameValue met dit voorbeeld uit met een SIGFPE.

    Code:
    ESign = FALSE
    EMant = 0
    EExp = 16383
    E2 =                           Nan
    Lazarus 1.8 komt wel met een resultaat:
    Code:
    ESign = FALSE
    EMant = 0
    EExp = 1023
    E2 =  8.9884656743115795E+307
    FALSE

  9. #9
    Quote Originally Posted by Bart B View Post
    Merkwaardig, wat doet BuildUp dan eigenlijk?
    YIKES. Waarom gebruik je eigenlijk Extended.Exp en niet Extended.Exponent.
    Met Extended.Exponent werkt het wel goed

    Code:
    ESign = FALSE
    EMant = 9223372036854775808
    EExponent = 0
    E2 =  1.00000000000000E+0000
    TRUE
    For assigning all bits of a TExtendedHelper variable with the values given by Sign, Mantissa, and Exponent, use the BuildUp method.
    Delphi Code:
    1. program Project11;
    2. {$APPTYPE CONSOLE}
    3. uses sysutils, math;
    4.  
    5. function TestExtendedBuildUp: Boolean;
    6. var
    7.   E1, E2: Extended;
    8.   ESign: Boolean;
    9.   EMant, EExponent: UInt64;
    10. begin
    11.   E1 := 1.0;
    12.   ESign := E1.Sign;
    13.   EMant := E1.Mantissa;
    14.   EExponent := E1.Exponent;
    15.   E2.BuildUp(ESign, EMant, EExponent);
    16.   Result := SameValue(E1, E2);
    17.   Writeln('ESign = ', ESign);
    18.   Writeln('EMant = ', EMant);
    19.   Writeln('EExponent = ', EExponent);
    20.   Writeln('E2 = ', E2);
    21. end;
    22.  
    23. begin
    24.   Write(TestExtendedBuildUp);
    25.   Readln;
    26. end.

    Represents the raw exponent part in the fraction number.
    Exp is represented on 15 bits.
    The Exp property provides direct access to the UInt64 exponent part of the floating-point value.
    The number 21, represented in binary, is 10101. After the normalization, the number looks like this: 1.0101 * 2^4.
    To calculate the Exp, the bias, 16384, is added to 4, the exponent after the normalization.
    Zoals ik het dus begrijp is Exp een raw type zoals die in de UInt64 gerepresenteerd is. Niet de "Exponent" die je werkelijk moet gebruiken voor BuildUp. Daar is dus Extended.Exponent voor.

    PS. Werkt in Lazarus dus ook goed want daar geeft ie nu ook TRUE
    Last edited by rvk; 17-Dec-17 at 01:24.

  10. #10
    Ik krijg dit:
    Code:
    EInvalidOp: Invalid floating point operation
      $004157F0
      $00401954  TESTEXTENDEDBUILDUP,  line 103 of fl.lpr  // -> call to SameValue
      $00401AB7  main,  line 160 of fl.lpr
    Als ik E2 door DbgS() haal krijg ik:
    Code:
    E1 =  1.00000000000000000000E+0000 Sign: +, Mantissa: 0000000000000000, Exp: 0000000000003FFF, Frac: 8000000000000000
    E2 =                           Nan Sign: +, Mantissa: 0000000000000000, Exp: 0000000000003FFF, Frac: 0000000000000000
    Bart

  11. #11
    Quote Originally Posted by Bart B View Post
    Ik krijg dit:
    EInvalidOp: Invalid floating point operation
    Heb je mijn laatste post gelezen?
    En Extended.Exponent gebruikt i.p.v. Extended.Exp ?

  12. #12
    Yep, jouw voorbeeldcode gekopiëerd.

    Bart

  13. #13
    Ik zie inderdaad hier dat Lazarus trunk (32 bit) nog steeds een probleem heeft met dit voorbeeld.
    Lazarus 1.8 64 bit doet het wel goed.
    (maar ik heb hier een oude trunk draaien)

    Ik zal morgen eens kijken wat de nieuwe trunk en trunk 64 doet en waarom Extended.Exponent met een ander resultaat komt dan Laz1.8.

  14. #14
    Maar weer eens terug naar het begin.
    Ik heb DbgS() aangepast om ook .Exponent te tonen.

    Code:
    E = 1.99975585937500000000 Sign: +, Mantissa: 7FF8000000000000, Exp: 3FFF, Exponent: 3C00, Frac: FFF8000000000000
    D = 1.99975585937500000000 Sign: +, Mantissa: 000FFF0000000000, Exp: 03FF, Exponent: 0000, Frac: 001FFF0000000000
    S = 1.99975585900000000000 Sign: +, Mantissa: 00000000007FF800, Exp: 007F, Exponent: FFFFFC80, Frac: 00000000087FF800
    Alleen de waarde voor Double klopt, hetgeen ook verklaart waarom jouw test op 64-bit slaagt, immers op 64-bit is Extended gemapt naar Double.

    De fout zit in

    Delphi Code:
    1. Function TFLOATHELPER.Exponent: Integer;
    2.  
    3. var
    4.   F,E : QWord;
    5. begin
    6.   Result:=0; // Zero, inf, Nan
    7.   E:=GetE;
    8.   F:=GetF;
    9.   if (0<E) and (E<$77FF) then
    10.     Result:=E-$3FF  //<<-- dit klopt alleen voor Double, waar Bias = $3FF
    11.   else if (E=0) and (F<>0) then
    12.     Result:=-1022
    13. end;

    Bart
    Last edited by Bart B; 17-Dec-17 at 23:56. Reason: typo in comment

  15. #15
    Ik heb een patch gepost voor de bug in TFloatHelper.Exponent in het betreffende bugtracker ticket.

    Bart
    Last edited by Bart B; 17-Dec-17 at 23:55. Reason: typo

Page 1 of 2 1 2 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •