Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2006-02

Floating-point number representation on various platforms

4 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Tom Verhoeff

While writing a paper (several years ago) about the traps of using floating-point numbers, I prepared a unit FloatView to "play" with the internal representation according to the IEEE Std, including to print it in various formats.

Initially, I made this work for the Linux/i386 platform only. Later, I tweaked it for Mac OS X (different byte order). It supports only the IEEE Std Single and Double format (not Extended).

I would like to make this unit available, but hesitate, because of its platform dependence (and currently limited platform support).

Question 1: Is there an interest in such a unit?

Question 2: Any suggestions as to how to make it more platform independent, or how to support multiple platforms in an easy way?

Looking forward to some feedback,

Tom Verhoeff

E-MAIL: T.Verhoeff @ TUE.NL | Fac. of Math. & Computing Science PHONE: +31 40 247 41 25 | Eindhoven University of Technology FAX: +31 40 247 54 04 | PO Box 513, NL-5600 MB Eindhoven http://www.win.tue.nl/~wstomv/ | The Netherlands
Jonas Maebe
to Tom Verhoeff
Tom Verhoeff wrote
Question 2: Any suggestions as to how to make it more platform independent, or how to support multiple platforms in an easy way?

The only differences are little/big endian. So if it works on PPC and I386, you have support for all platforms. Just use {$ifdef FPC_LITTLE_ENDIAN}

Jonas

Tom Verhoeff
to Jonas Maebe
Jonas Maebe wrote 10 lines
On 05 Feb 2006, at 13:32, Tom Verhoeff wrote: >Question 2: Any suggestions as to how to make it more platform >independent, >or how to support multiple platforms in an easy way? The only differences are little/big endian. So if it works on PPC and I386, you have support for all platforms. Just use {$ifdef FPC_LITTLE_ENDIAN}

[This is about IEEE floating-point numbers]

Two further questions.

Which platforms use which endian? (Of course, I could just experiment, or maybe even read the FPC source, but asking is simpler. :-)

When I looked at my code again, it seems to me that the change that I made to support both PPC and I386 is not endian-related, but I may be wrong, or it may be more complicated.

So, here are some pieces of the code, it uses a variant array to access the bits of the IEEE floating-point numbers in Single and Double: -----
interface

const
  SignIndexSingle =    31; { position of sign bit in single format }
  ExpSizeSingle   =     8; { size of exponent field in single format }
  MaxExpSingle    =   255;
  ExpBiasSingle   =   127;
  EminSingle      = 1 - ExpBiasSingle;
  EmaxSingle      = MaxExpSingle - 1 - ExpBiasSingle;
  FracSizeSingle  =    23; { size of fraction field in single format }
type
  BitIndexSingle = 0 .. SignIndexSingle;
  ConvertSingle = record
    case Boolean of
      False: ( d: Single )
    ; True : ( s: set of BitIndexSingle )  { i in s == bit i = 1 }
    end;
procedure WriteBitsSingle ( const x: Single );
procedure WriteBinarySingle ( const x: Single );
function PowerOf2Single ( const x: Single; n: Integer ): Single;
const
  SignIndexDouble =    63; { position of sign bit in double format }
  ExpSizeDouble   =    11; { size of exponent field in double format }
  MaxExpDouble    =  2047;
  ExpBiasDouble   =  1023;
  EminDouble      = 1 - ExpBiasDouble;
  EmaxDouble      = MaxExpSingle - 1 - ExpBiasDouble;
  FracSizeDouble  =    52; { size of fraction field in double format }
type
  BitIndexDouble = 0 .. SignIndexDouble;
  ConvertDouble = record
    case Boolean of
      False: ( d: Double )
    ; True : ( s: set of BitIndexDouble )  { i in s == bit i = 1 }
    end;
procedure WriteBitsDouble ( const x: Double );
procedure WriteBinaryDouble ( const x: Double );
procedure FlipBitDouble ( var x: Double; i: BitIndexDouble );
function PowerOf2Double ( const x: Double; n: Integer ): Double;
-----

It turns out that my code for the Single type works on both PPC and I386 without change. However for Double, I had to write e.g.

-----
procedure WriteBitsDouble ( const x: Double );
  var c: ConvertDouble; i, i_: BitIndexDouble;
  begin
    with c do begin
      d := x
    ; for i := SignIndexDouble downto 0 do begin
{$IFDEF CPUPOWERPC}
        i_ := (i + 32) mod 64
{$ENDIF}
{$IFDEF CPUI386}
        i_ := i
{$ENDIF}
      ; if i_ in s then write ( '1' )
        else write ( '0' )
      ; if i in [ SignIndexDouble, SignIndexDouble - ExpSizeDouble ] then
          write ( ' ' )
      end { for i }

end { with c }
end; { WriteBitsDouble }
-----

That is, the lower and upper 32 bits (4 bytes) got swapped.

Maybe this is the case because both the 64-bit set and the Double get allocated differently depending on endianess?

Can someone enlighten me?

Thanks,

Tom

E-MAIL: T.Verhoeff @ TUE.NL | Fac. of Math. & Computing Science PHONE: +31 40 247 41 25 | Eindhoven University of Technology FAX: +31 40 247 54 04 | PO Box 513, NL-5600 MB Eindhoven http://www.win.tue.nl/~wstomv/ | The Netherlands
Tom Verhoeff
to Tom Verhoeff
Tom Verhoeff wrote
So, here are some pieces of the code, it uses a variant array to access the bits of the IEEE floating-point numbers in Single and Double:

That should be 'record' insteady of 'array', of course.

Tom

E-MAIL: T.Verhoeff @ TUE.NL | Fac. of Math. & Computing Science PHONE: +31 40 247 41 25 | Eindhoven University of Technology FAX: +31 40 247 54 04 | PO Box 513, NL-5600 MB Eindhoven http://www.win.tue.nl/~wstomv/ | The Netherlands