real2str.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Michael Van Canneyt,
  5. member of the Free Pascal development team
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. type
  13. { See symdefh.inc tfloattyp }
  14. treal_type = (rt_s32real,rt_s64real,rt_s80real,rt_c64bit,rt_f16bit,rt_f32bit);
  15. { corresponding to single double extended fixed comp for i386 }
  16. const
  17. { do not use real constants else you get rouding errors }
  18. i10 : longint = 10;
  19. i2 : longint = 2;
  20. i1 : longint = 1;
  21. (*
  22. { we can use this conditional if the Inf const is defined
  23. in processor specific code PM }
  24. {$ifdef FPC_HAS_INFINITY_CONST}
  25. {$define FPC_INFINITY_FOR_REAL2STR}
  26. {$else not FPC_HAS_INFINITY_CONST}
  27. { To avoid problems with infinity just
  28. issue it in byte representation to be endianness independant PM }
  29. {$ifndef FPC_INFINITY_FOR_REAL2STR}
  30. {$ifdef SUPPORT_EXTENDED}
  31. { extended is not IEEE so its processor specific
  32. so I only allow it for i386 PM }
  33. {$ifdef i386}
  34. {$define FPC_INFINITY_FOR_REAL2STR}
  35. InfArray : {extended} array[0..9] of byte = ($0,$0,$0,$0,$0,$0,$0,$80,$ff,$7f);
  36. {$endif i386}
  37. {$endif SUPPORT_EXTENDED}
  38. {$endif not FPC_INFINITY_FOR_REAL2STR}
  39. {$ifndef FPC_INFINITY_FOR_REAL2STR}
  40. {$ifdef SUPPORT_DOUBLE}
  41. {$define FPC_INFINITY_FOR_REAL2STR}
  42. InfArray : {double} array[0..9] of byte = ($0,$0,$0,$0,$0,$0,$f0,$7f);
  43. {$endif SUPPORT_DOUBLE}
  44. {$endif not FPC_INFINITY_FOR_REAL2STR}
  45. {$ifndef FPC_INFINITY_FOR_REAL2STR}
  46. {$ifdef SUPPORT_SINGLE}
  47. {$define FPC_INFINITY_FOR_REAL2STR}
  48. InfArray : {single} array[0..3] of byte = ($0,$0,$80,$7f);
  49. {$endif SUPPORT_SINGLE}
  50. {$endif not FPC_INFINITY_FOR_REAL2STR}
  51. {$ifndef FPC_INFINITY_FOR_REAL2STR}
  52. {$warning don't know Infinity values }
  53. {$endif not FPC_INFINITY_FOR_REAL2STR}
  54. {$endif not FPC_HAS_INFINITY_CONST}
  55. *)
  56. Procedure str_real (len,f : longint; d : ValReal; real_type :treal_type; var s : string);
  57. {
  58. These numbers are for the double type...
  59. At the moment these are mapped onto a double but this may change
  60. in the future !
  61. }
  62. var maxlen : longint; { Maximal length of string for float }
  63. minlen : longint; { Minimal length of string for float }
  64. explen : longint; { Length of exponent, including E and sign.
  65. Must be strictly larger than 2 }
  66. const
  67. maxexp = 1e+35; { Maximum value for decimal expressions }
  68. minexp = 1e-35; { Minimum value for decimal expressions }
  69. zero = '0000000000000000000000000000000000000000';
  70. type
  71. TSplitExtended = packed record
  72. case byte of
  73. 0: (bytes: Array[0..9] of byte);
  74. 1: (words: Array[0..4] of word);
  75. 2: (cards: Array[0..1] of cardinal; w: word);
  76. end;
  77. TSplitDouble = packed record
  78. case byte of
  79. 0: (bytes: Array[0..7] of byte);
  80. 1: (words: Array[0..3] of word);
  81. 2: (cards: Array[0..1] of cardinal);
  82. end;
  83. TSplitSingle = packed record
  84. case byte of
  85. 0: (bytes: Array[0..3] of byte);
  86. 1: (words: Array[0..1] of word);
  87. 2: (cards: Array[0..0] of cardinal);
  88. end;
  89. var correct : longint; { Power correction }
  90. currprec : longint;
  91. il,il2,roundcorr : Valreal;
  92. temp : string;
  93. power : string[10];
  94. sign : boolean;
  95. i : integer;
  96. dot : byte;
  97. currp : pchar;
  98. mantZero, expMaximal: boolean;
  99. begin
  100. case real_type of
  101. rt_s32real :
  102. begin
  103. maxlen:=16;
  104. minlen:=8;
  105. explen:=4;
  106. end;
  107. rt_s64real :
  108. begin
  109. maxlen:=23;
  110. minlen:=9;
  111. explen:=5;
  112. end;
  113. rt_s80real :
  114. begin
  115. maxlen:=26;
  116. minlen:=10;
  117. explen:=6;
  118. end;
  119. rt_c64bit :
  120. begin
  121. maxlen:=22;
  122. minlen:=9;
  123. { according to TP (was 5) (FK) }
  124. explen:=6;
  125. end;
  126. rt_f16bit :
  127. begin
  128. maxlen:=16;
  129. minlen:=8;
  130. explen:=4;
  131. end;
  132. rt_f32bit :
  133. begin
  134. maxlen:=16;
  135. minlen:=8;
  136. explen:=4;
  137. end;
  138. end;
  139. { check parameters }
  140. { default value for length is -32767 }
  141. if len=-32767 then
  142. len:=maxlen;
  143. { determine sign. before precision, needs 2 less calls to abs() }
  144. { sign:=d<0;}
  145. {$ifndef big_endian}
  146. {$ifdef SUPPORT_EXTENDED}
  147. { extended, format (MSB): 1 Sign bit, 15 bit exponent, 64 bit mantissa }
  148. sign := (TSplitExtended(d).w and $8000) <> 0;
  149. expMaximal := (TSplitExtended(d).w and $7fff) = 32767;
  150. mantZero := (TSplitExtended(d).cards[0] = 0) and
  151. (TSplitExtended(d).cards[1] = 0);
  152. {$else SUPPORT_EXTENDED}
  153. {$ifdef SUPPORT_DOUBLE}
  154. { double, format (MSB): 1 Sign bit, 11 bit exponent, 52 bit mantissa }
  155. sign := ((TSplitDouble(d).cards[1] shr 20) and $800) <> 0;
  156. expMaximal := ((TSplitDouble(d).cards[1] shr 20) and $7ff) = 2047;
  157. mantZero := (TSplitDouble(d).cards[1] and $fffff = 0) and
  158. (TSplitDouble(d).cards[0] = 0);
  159. {$else SUPPORT_DOUBLE}
  160. {$ifdef SUPPORT_SINGLE}
  161. { single, format (MSB): 1 Sign bit, 8 bit exponent, 23 bit mantissa }
  162. sign := ((TSplitSingle(d).words[1] shr 7) and $100) <> 0;
  163. expMaximal := ((TSplitSingle(d).words[1] shr 7) and $ff) = 255;
  164. mantZero := (TSplitSingle(d).cards[0] and $7fffff = 0);
  165. {$else SUPPORT_SINGLE}
  166. {$error No floating type supported for real2str}
  167. {$endif SUPPORT_SINGLE}
  168. {$endif SUPPORT_DOUBLE}
  169. {$endif SUPPORT_EXTENDED}
  170. {$else big_endian}
  171. {$error NaN/Inf not yet supported for big endian machines in str_real}
  172. {$endif big_endian}
  173. if expMaximal then
  174. if mantZero then
  175. if sign then
  176. temp := '-Inf'
  177. else temp := 'Inf'
  178. else temp := 'NaN'
  179. else
  180. begin
  181. { the creates a cannot determine which overloaded function to call
  182. if d is extended !!!
  183. we should prefer real_to_real on real_to_longint !!
  184. corrected in compiler }
  185. { d:=abs(d); this converts d to double so we loose precision }
  186. { for the same reason I converted d:=frac(d) to d:=d-int(d); (PM) }
  187. if sign then
  188. d:=-d;
  189. (*
  190. {$ifdef FPC_INFINITY_FOR_REAL2STR}
  191. {$ifndef FPC_HAS_INFINITY_CONST}
  192. if d=ValReal(InfArray) then
  193. {$else FPC_HAS_INFINITY_CONST}
  194. if d=Inf then
  195. {$endif FPC_HAS_INFINITY_CONST}
  196. begin
  197. if sign then
  198. s:='-Inf'
  199. else
  200. s:='Inf';
  201. exit;
  202. end;
  203. {$endif FPC_INFINITY_FOR_REAL2STR}
  204. *)
  205. { determine precision : maximal precision is : }
  206. currprec:=maxlen-explen-3;
  207. { this is also the maximal number of decimals !!}
  208. if f>currprec then
  209. f:=currprec;
  210. { when doing a fixed-point, we need less characters.}
  211. if (f<0) or ( (d<>0) and ((d>maxexp) or (d<minexp))) then
  212. begin
  213. { determine maximal number of decimals }
  214. if (len>=0) and (len<minlen) then
  215. len:=minlen;
  216. if (len>0) and (len<maxlen) then
  217. currprec:=len-explen-3;
  218. end;
  219. { convert to standard form. }
  220. correct:=0;
  221. if d>=i10 then
  222. begin
  223. il:=i1;
  224. il2:=i10;
  225. repeat
  226. il:=il2;
  227. il2:=il*i10;
  228. inc(correct);
  229. until (d<il2);
  230. d:=d/il;
  231. end
  232. else
  233. if (d<1) and (d<>0) then
  234. begin
  235. while d<1 do
  236. begin
  237. d:=d*i10;
  238. dec(correct);
  239. end;
  240. end;
  241. { RoundOff }
  242. roundcorr:=extended(i1)/extended(i2);
  243. if f<0 then
  244. for i:=1 to currprec do roundcorr:=roundcorr/i10
  245. else
  246. begin
  247. if correct+f<0 then
  248. begin
  249. for i:=1 to abs(correct+f) do
  250. roundcorr:=roundcorr*i10;
  251. end
  252. else
  253. begin
  254. for i:=1 to correct+f do
  255. roundcorr:=roundcorr/i10;
  256. end;
  257. end;
  258. d:=d+roundcorr;
  259. { 0.99 + 0.05 > 1.0 ! Fix this by dividing the results >=10 first (PV) }
  260. while (d>=10.0) do
  261. begin
  262. d:=d/i10;
  263. inc(correct);
  264. end;
  265. { Now we have a standard expression : sign d *10^correct
  266. where 1<d<10 or d=0 ... }
  267. { get first character }
  268. currp:=pchar(@temp[1]);
  269. if sign then
  270. currp^:='-'
  271. else
  272. currp^:=' ';
  273. inc(currp);
  274. currp^:=chr(ord('0')+trunc(d));
  275. inc(currp);
  276. d:=d-int(d);
  277. { Start making the string }
  278. for i:=1 to currprec do
  279. begin
  280. d:=d*i10;
  281. currp^:=chr(ord('0')+trunc(d));
  282. inc(currp);
  283. d:=d-int(d);
  284. end;
  285. temp[0]:=chr(currp-pchar(@temp[1]));
  286. { Now we need two different schemes for the different
  287. representations. }
  288. if (f<0) or (correct>maxexp) then
  289. begin
  290. insert ('.',temp,3);
  291. str(abs(correct),power);
  292. if length(power)<explen-2 then
  293. power:=copy(zero,1,explen-2-length(power))+power;
  294. if correct<0 then
  295. power:='-'+power
  296. else
  297. power:='+'+power;
  298. temp:=temp+'E'+power;
  299. end
  300. else
  301. begin
  302. if not sign then
  303. begin
  304. delete (temp,1,1);
  305. dot:=2;
  306. end
  307. else
  308. dot:=3;
  309. { set zeroes and dot }
  310. if correct>=0 then
  311. begin
  312. if length(temp)<correct+dot+f then
  313. temp:=temp+copy(zero,1,correct+dot+f-length(temp));
  314. insert ('.',temp,correct+dot);
  315. end
  316. else
  317. begin
  318. correct:=abs(correct);
  319. insert(copy(zero,1,correct),temp,dot-1);
  320. insert ('.',temp,dot);
  321. end;
  322. { correct length to fit precision }
  323. if f>0 then
  324. temp[0]:=chr(pos('.',temp)+f)
  325. else
  326. temp[0]:=chr(pos('.',temp)-1);
  327. end;
  328. end;
  329. if length(temp)<len then
  330. s:=space(len-length(temp))+temp
  331. else
  332. s:=temp;
  333. end;
  334. {
  335. $Log$
  336. Revision 1.20 2000-01-17 13:00:51 jonas
  337. + support for NaN's, cleaner support for Inf
  338. Revision 1.19 2000/01/07 16:41:36 daniel
  339. * copyright 2000
  340. Revision 1.18 1999/11/28 23:57:23 pierre
  341. * Infinite loop for infinite value problem fixed
  342. Revision 1.17 1999/11/03 09:54:24 peter
  343. * another fix for precision
  344. Revision 1.16 1999/11/03 00:55:09 pierre
  345. * problem of last commit for large d values corrected
  346. Revision 1.15 1999/11/02 15:05:53 peter
  347. * better precisio by dividing only once with a calculated longint
  348. instead of multiple times by 10
  349. Revision 1.14 1999/08/03 21:58:44 peter
  350. * small speed improvements
  351. Revision 1.13 1999/05/06 09:05:12 peter
  352. * generic write_float str_float
  353. Revision 1.12 1999/03/10 21:49:02 florian
  354. * str and val for extended use now int constants to minimize
  355. rounding error
  356. Revision 1.11 1999/02/16 00:49:20 peter
  357. * fixed rounding when correct+f < 0
  358. Revision 1.10 1998/08/11 21:39:06 peter
  359. * splitted default_extended from support_extended
  360. Revision 1.9 1998/08/11 00:05:25 peter
  361. * $ifdef ver0_99_5 updates
  362. Revision 1.8 1998/08/10 15:56:30 peter
  363. * fixed 0_9_5 typo
  364. Revision 1.7 1998/08/08 12:28:12 florian
  365. * a lot small fixes to the extended data type work
  366. Revision 1.6 1998/07/18 17:14:22 florian
  367. * strlenint type implemented
  368. Revision 1.5 1998/07/13 21:19:10 florian
  369. * some problems with ansi string support fixed
  370. Revision 1.4 1998/06/18 08:15:33 michael
  371. + Fixed error when printing zero. len was calculated wron.
  372. Revision 1.3 1998/05/12 10:42:45 peter
  373. * moved getopts to inc/, all supported OS's need argc,argv exported
  374. + strpas, strlen are now exported in the systemunit
  375. * removed logs
  376. * removed $ifdef ver_above
  377. Revision 1.2 1998/04/07 22:40:46 florian
  378. * final fix of comp writing
  379. }