flt_pack.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. {
  2. This file isolates platform-specific routines which perform packing and
  3. unpacking of ValReal FP values during float <-> ASCII conversions.
  4. These routines, mostly, were gathered from various places of FPC RTL.
  5. ****************************************************************************
  6. }
  7. {
  8. Note about inlining: since unpack_float is used only once in str_real,
  9. it can be safely inlined; however pack_float is used several times in
  10. val_real, so its inlining does not seem practical, except of the case
  11. when this procedure simply calls the SoftFPU implementation.
  12. }
  13. // ---------------------------------------------------------------------
  14. //
  15. // single; format [MSB]: 1 sign bit, 8 bit exponent, 23 bit mantissa
  16. //
  17. // ---------------------------------------------------------------------
  18. {$if defined(VALREAL_32) and not defined(VALREAL_PACK)}
  19. {$if defined(fpc_softfpu_implementation)
  20. or ( defined(FPC_SYSTEM_HAS_extractFloat32Frac)
  21. and defined(FPC_SYSTEM_HAS_extractFloat32Exp)
  22. and defined(FPC_SYSTEM_HAS_extractFloat32Sign)
  23. )}
  24. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  25. begin
  26. unpack_float.f := extractFloat32Frac( float32( f ) );
  27. unpack_float.e := extractFloat32Exp( float32( f ) );
  28. minus := ( extractFloat32Sign( float32( f ) ) <> 0 );
  29. end;
  30. {$else not fpc_softfpu_implementation}
  31. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  32. type
  33. TSplitFloat = packed record
  34. case byte of
  35. 0: ( f: ValReal );
  36. 1: ( b: array [ 0 .. 3 ] of byte );
  37. 2: ( w: array [ 0 .. 1 ] of word );
  38. 3: ( d: dword );
  39. end;
  40. var
  41. split: TSplitFloat;
  42. begin
  43. split.f := f;
  44. {$ifdef endian_big}
  45. minus := ( split.b[0] and $80 <> 0 );
  46. unpack_float.e := ( split.w[0] shr 7 ) and $FF;
  47. {$else endian_little}
  48. minus := ( split.b[3] and $80 <> 0 );
  49. unpack_float.e := ( split.w[1] shr 7 ) and $FF;
  50. {$endif endian}
  51. unpack_float.f := split.d and $007FFFFF;
  52. end;
  53. {$endif fpc_softfpu_implementation}
  54. {$endif unpack float32}
  55. {$if defined(VALREAL_32) and defined(VALREAL_PACK)}
  56. {$ifdef fpc_softfpu_implementation}
  57. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: dword ); {$ifdef grisu1_inline}inline;{$endif}
  58. begin
  59. f := float32rec( packFloat32( ord(minus), exp, m ) );
  60. end;
  61. {$else not fpc_softfpu_implementation}
  62. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; m: dword ); // {$ifdef grisu1_inline}inline;{$endif}
  63. type
  64. TSplitFloat = packed record
  65. case byte of
  66. 0: ( f: ValReal );
  67. 1: ( b: array [ 0 .. 3 ] of byte );
  68. 2: ( w: array [ 0 .. 1 ] of word );
  69. 3: ( d: dword );
  70. end;
  71. var
  72. split: TSplitFloat;
  73. begin
  74. split.d := m;
  75. {$ifdef endian_big}
  76. split.w[0] := split.w[0] + ( exp and $FF ) shl 7;
  77. if minus then
  78. split.b[0] := split.b[0] or $80;
  79. {$else endian_little}
  80. split.w[1] := split.w[1] + ( exp and $FF ) shl 7;
  81. if minus then
  82. split.b[3] := split.b[3] or $80;
  83. {$endif endian}
  84. f := split.f;
  85. end;
  86. {$endif fpc_softfpu_implementation}
  87. {$endif pack float32}
  88. // ---------------------------------------------------------------------
  89. //
  90. // double; format [MSB]: 1 sign bit, 11 bit exponent, 52 bit mantissa
  91. //
  92. // ---------------------------------------------------------------------
  93. {$if defined(VALREAL_64) and not defined(VALREAL_PACK)}
  94. {$ifdef cpujvm}
  95. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  96. var
  97. doublebits: int64;
  98. begin
  99. doublebits := JLDouble.doubleToLongBits( f );
  100. minus := ( doublebits < 0 );
  101. unpack_float.e := ( doublebits shr 52 ) and $7FF;
  102. unpack_float.f := ( doublebits and $000FFFFFFFFFFFFF );
  103. end;
  104. {$else not cpujvm}
  105. {$if defined(fpc_softfpu_implementation)
  106. or ( defined(FPC_SYSTEM_HAS_extractFloat64Frac)
  107. and defined(FPC_SYSTEM_HAS_extractFloat64Exp)
  108. and defined(FPC_SYSTEM_HAS_extractFloat64Sign)
  109. )}
  110. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  111. begin
  112. unpack_float.f := extractFloat64Frac( float64( f ) );
  113. unpack_float.e := extractFloat64Exp( float64( f ) );
  114. minus := ( extractFloat64Sign( float64( f ) ) <> 0 );
  115. end;
  116. {$else not fpc_softfpu_implementation}
  117. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  118. type
  119. TSplitFloat = packed record
  120. case byte of
  121. 0: ( f: ValReal );
  122. 1: ( b: array [ 0 .. 7 ] of byte );
  123. 2: ( w: array [ 0 .. 3 ] of word );
  124. 3: ( d: array [ 0 .. 1 ] of dword );
  125. 4: ( l: qword );
  126. end;
  127. var
  128. doublebits: TSplitFloat;
  129. begin
  130. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  131. // high and low dword are swapped when using the arm fpa
  132. doublebits.d[0] := TSplitFloat(f).d[1];
  133. doublebits.d[1] := TSplitFloat(f).d[0];
  134. {$else not FPC_DOUBLE_HILO_SWAPPED}
  135. doublebits.f := f;
  136. {$endif FPC_DOUBLE_HILO_SWAPPED}
  137. {$ifdef endian_big}
  138. minus := ( doublebits.b[0] and $80 <>0 );
  139. unpack_float.e := ( doublebits.w[0] shr 4 ) and $7FF;
  140. {$else endian_little}
  141. minus := ( doublebits.b[7] and $80 <> 0 );
  142. unpack_float.e := ( doublebits.w[3] shr 4 ) and $7FF;
  143. {$endif endian}
  144. unpack_float.f := doublebits.l and $000FFFFFFFFFFFFF;
  145. end;
  146. {$endif fpc_softfpu_implementation}
  147. {$endif cpujvm}
  148. {$endif unpack float64}
  149. {$if defined(VALREAL_64) and defined(VALREAL_PACK)}
  150. {$ifdef cpujvm}
  151. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); {$ifdef grisu1_inline}inline;{$endif}
  152. var
  153. doublebits: int64;
  154. begin
  155. doublebits := ( m and $000FFFFFFFFFFFFF ) + ( qword( exp and $7FF ) shl 52 ) + ( qword( ord(minus) ) shl 63 );
  156. f := JLDouble.longBitsToDouble( doublebits );
  157. end;
  158. {$else not cpujvm}
  159. {$ifdef fpc_softfpu_implementation}
  160. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); {$ifdef grisu1_inline}inline;{$endif}
  161. begin
  162. f := packFloat64( ord(minus), exp, m );
  163. end;
  164. {$else not fpc_softfpu_implementation}
  165. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); // {$ifdef grisu1_inline}inline;{$endif}
  166. type
  167. TSplitFloat = packed record
  168. case byte of
  169. 0: ( f: ValReal );
  170. 1: ( b: array [ 0 .. 7 ] of byte );
  171. 2: ( w: array [ 0 .. 3 ] of word );
  172. 3: ( d: array [ 0 .. 1 ] of dword );
  173. 4: ( l: qword );
  174. end;
  175. var
  176. doublebits: TSplitFloat;
  177. begin
  178. doublebits.l := m;
  179. {$ifdef endian_big}
  180. doublebits.w[0] := doublebits.w[0] + ( exp and $7FF ) shl 4;
  181. if minus then
  182. doublebits.b[0] := doublebits.b[0] or $80;
  183. {$else endian_little}
  184. doublebits.w[3] := doublebits.w[3] + ( exp and $7FF ) shl 4;
  185. if minus then
  186. doublebits.b[7] := doublebits.b[7] or $80;
  187. {$endif endian}
  188. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  189. // high and low dword are swapped when using the arm fpa
  190. TSplitFloat(f).d[1] := doublebits.d[0];
  191. TSplitFloat(f).d[0] := doublebits.d[1];
  192. {$else not FPC_DOUBLE_HILO_SWAPPED}
  193. f := doublebits.f;
  194. {$endif FPC_DOUBLE_HILO_SWAPPED}
  195. end;
  196. {$endif fpc_softfpu_implementation}
  197. {$endif cpujvm}
  198. {$endif pack float64}
  199. // ---------------------------------------------------------------------
  200. //
  201. // extended; format [MSB]: 1 Sign bit, 15 bit exponent, 64 bit mantissa (explicit integer bit is included)
  202. //
  203. // ---------------------------------------------------------------------
  204. {$if defined(VALREAL_80) and not defined(VALREAL_PACK)}
  205. {$ifdef fpc_softfpu_implementation}
  206. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  207. begin
  208. unpack_float.fh := 0;
  209. unpack_float.f := extractFloatx80Frac( f );
  210. unpack_float.e := extractFloatx80Exp( f );
  211. minus := ( extractFloatx80Sign( f ) <> 0 );
  212. end;
  213. {$else not fpc_softfpu_implementation}
  214. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  215. type
  216. TSplitFloat = packed record
  217. case byte of
  218. 0: ( f: ValReal );
  219. 1: ( b: array [ 0 .. 9 ] of byte );
  220. 2: ( l: qword; e: word )
  221. end;
  222. var
  223. split: TSplitFloat;
  224. begin
  225. split.f := f;
  226. {$ifdef endian_big}
  227. {$error Big endian extended double [80-bit] is not implemented}
  228. {$else endian_little}
  229. minus := ( split.b[9] and $80 <> 0 );
  230. unpack_float.e := split.e and $7FFF;
  231. unpack_float.f := split.l;
  232. unpack_float.fh := 0;
  233. {$endif endian}
  234. end;
  235. {$endif fpc_softfpu_implementation}
  236. {$endif unpack floatx80}
  237. {$if defined(VALREAL_80) and defined(VALREAL_PACK)}
  238. {$ifdef fpc_softfpu_implementation}
  239. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); {$ifdef grisu1_inline}inline;{$endif}
  240. begin
  241. f := packFloatx80( ord(minus), exp, m );
  242. end;
  243. {$else not fpc_softfpu_implementation}
  244. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const m: qword ); // {$ifdef grisu1_inline}inline;{$endif}
  245. type
  246. TSplitFloat = packed record
  247. case byte of
  248. 0: ( f: ValReal );
  249. 1: ( b: array [ 0 .. 9 ] of byte );
  250. 2: ( l: qword; e: word )
  251. end;
  252. var
  253. split: TSplitFloat;
  254. begin
  255. {$ifdef endian_big}
  256. {$error Big endian extended double [80-bit] is not implemented}
  257. {$else endian_little}
  258. split.l := m;
  259. split.e := exp and $7FFF;
  260. if minus then
  261. split.b[9] := split.b[9] or $80;
  262. {$endif endian}
  263. f := split.f;
  264. end;
  265. {$endif fpc_softfpu_implementation}
  266. {$endif pack floatx80}
  267. // ---------------------------------------------------------------------
  268. //
  269. // float128; format [MSB]: 1 Sign bit, 15 bit exponent, 112 bit mantissa
  270. //
  271. // ---------------------------------------------------------------------
  272. {$if defined(VALREAL_128) and not defined(VALREAL_PACK)}
  273. {$ifdef fpc_softfpu_implementation}
  274. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  275. begin
  276. unpack_float.fh := extractFloat128Frac0( f );
  277. unpack_float.f := extractFloat128Frac1( f );
  278. unpack_float.e := extractFloat128Exp( f );
  279. minus := ( extractFloat128Sign( f ) <> 0 );
  280. end;
  281. {$else not fpc_softfpu_implementation}
  282. function unpack_float( const f: ValReal; out minus: boolean ): TDIY_FP; {$ifdef grisu1_inline}inline;{$endif}
  283. type
  284. TSplitFloat = packed record
  285. case byte of
  286. 0: ( f: ValReal );
  287. 1: ( b: array [ 0 .. 15 ] of byte );
  288. 2: ( w: array [ 0 .. 7 ] of word );
  289. 3: ( l: array [ 0 .. 1 ] of qword );
  290. end;
  291. var
  292. split: TSplitFloat;
  293. begin
  294. split.f := f;
  295. {$ifdef endian_big}
  296. {$error Big endian long double [128-bit] is not implemented}
  297. {$else endian_little}
  298. minus := ( split.b[15] and $80 <> 0 );
  299. unpack_float.e := split.w[7] and $7FFF;
  300. unpack_float.f := split.l[0];
  301. unpack_float.fh := split.l[1] and $0000FFFFFFFFFFFF;
  302. {$endif endian}
  303. end;
  304. {$endif fpc_softfpu_implementation}
  305. {$endif unpack float128}
  306. {$if defined(VALREAL_128) and defined(VALREAL_PACK)}
  307. {$ifdef fpc_softfpu_implementation}
  308. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const h, l: qword ); {$ifdef grisu1_inline}inline;{$endif}
  309. begin
  310. f := packFloat128( ord(minus), exp, h, l );
  311. end;
  312. {$else not fpc_softfpu_implementation}
  313. procedure pack_float( out f: ValReal; minus: boolean; exp: integer; const h, l: qword ); // {$ifdef grisu1_inline}inline;{$endif}
  314. type
  315. TSplitFloat = packed record
  316. case byte of
  317. 0: ( f: ValReal );
  318. 1: ( b: array [ 0 .. 15 ] of byte );
  319. 2: ( w: array [ 0 .. 7 ] of word );
  320. 3: ( l: array [ 0 .. 1 ] of qword );
  321. end;
  322. var
  323. split: TSplitFloat;
  324. begin
  325. {$ifdef endian_big}
  326. {$error Big endian long double [128-bit] is not implemented}
  327. {$else endian_little}
  328. split.l[0] := l;
  329. split.l[1] := h;
  330. split.w[7] := exp and $7FFF;
  331. if minus then
  332. split.b[15] := split.b[15] or $80;
  333. {$endif endian}
  334. f := split.f;
  335. end;
  336. {$endif fpc_softfpu_implementation}
  337. {$endif pack float128}