real2str.inc 6.7 KB

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