real2str.inc 7.4 KB

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