real2str.inc 9.2 KB

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