123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- {
- This file isolates platform-specific routines which perform packing and
- unpacking of ValReal FP values during float <-> ASCII conversions.
- These routines, mostly, were gathered from various places of FPC RTL.
- ****************************************************************************
- }
- {
- Note about inlining: since unpack_float is used only once in str_real,
- it can be safely inlined; however pack_float is used several times in
- val_real, so its inlining does not seem practical, except of the case
- when this procedure simply calls the SoftFPU implementation.
- }
- // ---------------------------------------------------------------------
- //
- // single; format [MSB]: 1 sign bit, 8 bit exponent, 23 bit mantissa
- //
- // ---------------------------------------------------------------------
- {$if defined(VALREAL_32) and not defined(VALREAL_PACK)}
- {$if defined(fpc_softfpu_implementation)
- or ( defined(FPC_SYSTEM_HAS_extractFloat32Frac)
- and defined(FPC_SYSTEM_HAS_extractFloat32Exp)
- and defined(FPC_SYSTEM_HAS_extractFloat32Sign)
- )}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- begin
- unpack_float.f := extractFloat32Frac( float32( f ) );
- unpack_float.e := extractFloat32Exp( float32( f ) );
- minus := ( extractFloat32Sign( float32( f ) ) <> 0 );
- end;
- {$else not fpc_softfpu_implementation}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- type
- TSplitFloat = packed record
- case byte of
- 0: ( f: ValReal );
- 1: ( b: array [ 0 .. 3 ] of byte );
- 2: ( w: array [ 0 .. 1 ] of word );
- 3: ( d: dword );
- end;
- var
- split: TSplitFloat;
- begin
- split.f := f;
- {$ifdef endian_big}
- minus := ( split.b[0] and $80 <> 0 );
- unpack_float.e := ( split.w[0] shr 7 ) and $FF;
- {$else endian_little}
- minus := ( split.b[3] and $80 <> 0 );
- unpack_float.e := ( split.w[1] shr 7 ) and $FF;
- {$endif endian}
- unpack_float.f := split.d and $007FFFFF;
- end;
- {$endif fpc_softfpu_implementation}
- {$endif unpack float32}
- {$if defined(VALREAL_32) and defined(VALREAL_PACK)}
- {$ifdef fpc_softfpu_implementation}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: dword ); {$ifdef grisu1_inline}inline;{$endif}
- begin
- f := float32rec( packFloat32( ord(minus), exp, m ) );
- end;
- {$else not fpc_softfpu_implementation}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; m: dword ); // {$ifdef grisu1_inline}inline;{$endif}
- type
- TSplitFloat = packed record
- case byte of
- 0: ( f: ValReal );
- 1: ( b: array [ 0 .. 3 ] of byte );
- 2: ( w: array [ 0 .. 1 ] of word );
- 3: ( d: dword );
- end;
- var
- split: TSplitFloat;
- begin
- split.d := m;
- {$ifdef endian_big}
- split.w[0] := split.w[0] + ( exp and $FF ) shl 7;
- if minus then
- split.b[0] := split.b[0] or $80;
- {$else endian_little}
- split.w[1] := split.w[1] + ( exp and $FF ) shl 7;
- if minus then
- split.b[3] := split.b[3] or $80;
- {$endif endian}
- f := split.f;
- end;
- {$endif fpc_softfpu_implementation}
- {$endif pack float32}
- // ---------------------------------------------------------------------
- //
- // double; format [MSB]: 1 sign bit, 11 bit exponent, 52 bit mantissa
- //
- // ---------------------------------------------------------------------
- {$if defined(VALREAL_64) and not defined(VALREAL_PACK)}
- {$ifdef cpujvm}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- var
- doublebits: int64;
- begin
- doublebits := JLDouble.doubleToLongBits( f );
- minus := ( doublebits < 0 );
- unpack_float.e := ( doublebits shr 52 ) and $7FF;
- unpack_float.f := ( doublebits and $000FFFFFFFFFFFFF );
- end;
- {$else not cpujvm}
- {$if defined(fpc_softfpu_implementation)
- or ( defined(FPC_SYSTEM_HAS_extractFloat64Frac)
- and defined(FPC_SYSTEM_HAS_extractFloat64Exp)
- and defined(FPC_SYSTEM_HAS_extractFloat64Sign)
- )}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- begin
- unpack_float.f := extractFloat64Frac( float64( f ) );
- unpack_float.e := extractFloat64Exp( float64( f ) );
- minus := ( extractFloat64Sign( float64( f ) ) <> 0 );
- end;
- {$else not fpc_softfpu_implementation}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- type
- TSplitFloat = packed record
- case byte of
- 0: ( f: ValReal );
- 1: ( b: array [ 0 .. 7 ] of byte );
- 2: ( w: array [ 0 .. 3 ] of word );
- 3: ( d: array [ 0 .. 1 ] of dword );
- 4: ( l: qword );
- end;
- var
- doublebits: TSplitFloat;
- begin
- {$ifdef FPC_DOUBLE_HILO_SWAPPED}
- // high and low dword are swapped when using the arm fpa
- doublebits.d[0] := TSplitFloat(f).d[1];
- doublebits.d[1] := TSplitFloat(f).d[0];
- {$else not FPC_DOUBLE_HILO_SWAPPED}
- doublebits.f := f;
- {$endif FPC_DOUBLE_HILO_SWAPPED}
- {$ifdef endian_big}
- minus := ( doublebits.b[0] and $80 <>0 );
- unpack_float.e := ( doublebits.w[0] shr 4 ) and $7FF;
- {$else endian_little}
- minus := ( doublebits.b[7] and $80 <> 0 );
- unpack_float.e := ( doublebits.w[3] shr 4 ) and $7FF;
- {$endif endian}
- unpack_float.f := doublebits.l and $000FFFFFFFFFFFFF;
- end;
- {$endif fpc_softfpu_implementation}
- {$endif cpujvm}
- {$endif unpack float64}
- {$if defined(VALREAL_64) and defined(VALREAL_PACK)}
- {$ifdef cpujvm}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); {$ifdef grisu1_inline}inline;{$endif}
- var
- doublebits: int64;
- begin
- doublebits := ( m and $000FFFFFFFFFFFFF ) + ( qword( exp and $7FF ) shl 52 ) + ( qword( ord(minus) ) shl 63 );
- f := JLDouble.longBitsToDouble( doublebits );
- end;
- {$else not cpujvm}
- {$ifdef fpc_softfpu_implementation}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); {$ifdef grisu1_inline}inline;{$endif}
- begin
- f := packFloat64( ord(minus), exp, m );
- end;
- {$else not fpc_softfpu_implementation}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); // {$ifdef grisu1_inline}inline;{$endif}
- type
- TSplitFloat = packed record
- case byte of
- 0: ( f: ValReal );
- 1: ( b: array [ 0 .. 7 ] of byte );
- 2: ( w: array [ 0 .. 3 ] of word );
- 3: ( d: array [ 0 .. 1 ] of dword );
- 4: ( l: qword );
- end;
- var
- doublebits: TSplitFloat;
- begin
- doublebits.l := m;
- {$ifdef endian_big}
- doublebits.w[0] := doublebits.w[0] + ( exp and $7FF ) shl 4;
- if minus then
- doublebits.b[0] := doublebits.b[0] or $80;
- {$else endian_little}
- doublebits.w[3] := doublebits.w[3] + ( exp and $7FF ) shl 4;
- if minus then
- doublebits.b[7] := doublebits.b[7] or $80;
- {$endif endian}
- {$ifdef FPC_DOUBLE_HILO_SWAPPED}
- // high and low dword are swapped when using the arm fpa
- TSplitFloat(f).d[1] := doublebits.d[0];
- TSplitFloat(f).d[0] := doublebits.d[1];
- {$else not FPC_DOUBLE_HILO_SWAPPED}
- f := doublebits.f;
- {$endif FPC_DOUBLE_HILO_SWAPPED}
- end;
- {$endif fpc_softfpu_implementation}
- {$endif cpujvm}
- {$endif pack float64}
- // ---------------------------------------------------------------------
- //
- // extended; format [MSB]: 1 Sign bit, 15 bit exponent, 64 bit mantissa (explicit integer bit is included)
- //
- // ---------------------------------------------------------------------
- {$if defined(VALREAL_80) and not defined(VALREAL_PACK)}
- {$ifdef fpc_softfpu_implementation}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- begin
- unpack_float.fh := 0;
- unpack_float.f := extractFloatx80Frac( f );
- unpack_float.e := extractFloatx80Exp( f );
- minus := ( extractFloatx80Sign( f ) <> 0 );
- end;
- {$else not fpc_softfpu_implementation}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- type
- TSplitFloat = packed record
- case byte of
- 0: ( f: ValReal );
- 1: ( b: array [ 0 .. 9 ] of byte );
- 2: ( l: qword; e: word )
- end;
- var
- split: TSplitFloat;
- begin
- split.f := f;
- {$ifdef endian_big}
- {$error Big endian extended double [80-bit] is not implemented}
- {$else endian_little}
- minus := ( split.b[9] and $80 <> 0 );
- unpack_float.e := split.e and $7FFF;
- unpack_float.f := split.l;
- unpack_float.fh := 0;
- {$endif endian}
- end;
- {$endif fpc_softfpu_implementation}
- {$endif unpack floatx80}
- {$if defined(VALREAL_80) and defined(VALREAL_PACK)}
- {$ifdef fpc_softfpu_implementation}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); {$ifdef grisu1_inline}inline;{$endif}
- begin
- f := packFloatx80( ord(minus), exp, m );
- end;
- {$else not fpc_softfpu_implementation}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); // {$ifdef grisu1_inline}inline;{$endif}
- type
- TSplitFloat = packed record
- case byte of
- 0: ( f: ValReal );
- 1: ( b: array [ 0 .. 9 ] of byte );
- 2: ( l: qword; e: word )
- end;
- var
- split: TSplitFloat;
- begin
- {$ifdef endian_big}
- {$error Big endian extended double [80-bit] is not implemented}
- {$else endian_little}
- split.l := m;
- split.e := exp and $7FFF;
- if minus then
- split.b[9] := split.b[9] or $80;
- {$endif endian}
- f := split.f;
- end;
- {$endif fpc_softfpu_implementation}
- {$endif pack floatx80}
- // ---------------------------------------------------------------------
- //
- // float128; format [MSB]: 1 Sign bit, 15 bit exponent, 112 bit mantissa
- //
- // ---------------------------------------------------------------------
- {$if defined(VALREAL_128) and not defined(VALREAL_PACK)}
- {$ifdef fpc_softfpu_implementation}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- begin
- unpack_float.fh := extractFloat128Frac0( f );
- unpack_float.f := extractFloat128Frac1( f );
- unpack_float.e := extractFloat128Exp( f );
- minus := ( extractFloat128Sign( f ) <> 0 );
- end;
- {$else not fpc_softfpu_implementation}
- function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
- type
- TSplitFloat = packed record
- case byte of
- 0: ( f: ValReal );
- 1: ( b: array [ 0 .. 15 ] of byte );
- 2: ( w: array [ 0 .. 7 ] of word );
- 3: ( l: array [ 0 .. 1 ] of qword );
- end;
- var
- split: TSplitFloat;
- begin
- split.f := f;
- {$ifdef endian_big}
- {$error Big endian long double [128-bit] is not implemented}
- {$else endian_little}
- minus := ( split.b[15] and $80 <> 0 );
- unpack_float.e := split.w[7] and $7FFF;
- unpack_float.f := split.l[0];
- unpack_float.fh := split.l[1] and $0000FFFFFFFFFFFF;
- {$endif endian}
- end;
- {$endif fpc_softfpu_implementation}
- {$endif unpack float128}
- {$if defined(VALREAL_128) and defined(VALREAL_PACK)}
- {$ifdef fpc_softfpu_implementation}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const h, l: qword ); {$ifdef grisu1_inline}inline;{$endif}
- begin
- f := packFloat128( ord(minus), exp, h, l );
- end;
- {$else not fpc_softfpu_implementation}
- procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const h, l: qword ); // {$ifdef grisu1_inline}inline;{$endif}
- type
- TSplitFloat = packed record
- case byte of
- 0: ( f: ValReal );
- 1: ( b: array [ 0 .. 15 ] of byte );
- 2: ( w: array [ 0 .. 7 ] of word );
- 3: ( l: array [ 0 .. 1 ] of qword );
- end;
- var
- split: TSplitFloat;
- begin
- {$ifdef endian_big}
- {$error Big endian long double [128-bit] is not implemented}
- {$else endian_little}
- split.l[0] := l;
- split.l[1] := h;
- split.w[7] := exp and $7FFF;
- if minus then
- split.b[15] := split.b[15] or $80;
- {$endif endian}
- f := split.f;
- end;
- {$endif fpc_softfpu_implementation}
- {$endif pack float128}
|