Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

347 lines
10 KiB

  1. /***
  2. *x10fout.c - floating point output for 10-byte long double
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Support conversion of a long double into a string
  8. *
  9. *Revision History:
  10. * 07/15/91 GDP Initial version in C (ported from assembly)
  11. * 01/23/92 GDP Support MIPS encoding for NaN
  12. *
  13. *******************************************************************************/
  14. #include <string.h>
  15. #include <cv.h>
  16. #define STRCPY strcpy
  17. #define PUT_ZERO_FOS(fos) \
  18. fos->exp = 0, \
  19. fos->sign = ' ', \
  20. fos->ManLen = 1, \
  21. fos->man[0] = '0',\
  22. fos->man[1] = 0;
  23. #define SNAN_STR "1#SNAN"
  24. #define SNAN_STR_LEN 6
  25. #define QNAN_STR "1#QNAN"
  26. #define QNAN_STR_LEN 6
  27. #define INF_STR "1#INF"
  28. #define INF_STR_LEN 5
  29. #define IND_STR "1#IND"
  30. #define IND_STR_LEN 5
  31. /***
  32. *int _CALLTYPE5
  33. * _$i10_output(_LDOUBLE ld,
  34. * int ndigits,
  35. * unsigned output_flags,
  36. * FOS *fos) - output conversion of a 10-byte _LDOUBLE
  37. *
  38. *Purpose:
  39. * Fill in a FOS structure for a given _LDOUBLE
  40. *
  41. *Entry:
  42. * _LDOUBLE ld: The long double to be converted into a string
  43. * int ndigits: number of digits allowed in the output format.
  44. * unsigned output_flags: The following flags can be used:
  45. * SO_FFORMAT: Indicates 'f' format
  46. * (default is 'e' format)
  47. * FOS *fos: the structure that i10_output will fill in
  48. *
  49. *Exit:
  50. * modifies *fos
  51. * return 1 if original number was ok, 0 otherwise (infinity, NaN, etc)
  52. *
  53. *Exceptions:
  54. *
  55. *******************************************************************************/
  56. int _CALLTYPE5 $I10_OUTPUT(_LDOUBLE ld, int ndigits,
  57. unsigned output_flags, FOS *fos)
  58. {
  59. u_short expn;
  60. u_long manhi,manlo;
  61. u_short sign;
  62. /* useful constants (see algorithm explanation below) */
  63. u_short const log2hi = 0x4d10;
  64. u_short const log2lo = 0x4d;
  65. u_short const log4hi = 0x9a;
  66. u_long const c = 0x134312f4;
  67. #if defined(L_END)
  68. _LDBL12 ld12_one_tenth = {
  69. {0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,
  70. 0xcc,0xcc,0xcc,0xcc,0xfb,0x3f}
  71. };
  72. #elif defined(B_END)
  73. _LDBL12 ld12_one_tenth = {
  74. {0x3f,0xfb,0xcc,0xcc,0xcc,0xcc,
  75. 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc}
  76. };
  77. #endif
  78. _LDBL12 ld12; /* space for a 12-byte long double */
  79. _LDBL12 tmp12;
  80. u_short hh,ll; /* the bytes of the exponent grouped in 2 words*/
  81. u_short mm; /* the two MSBytes of the mantissa */
  82. s_long r; /* the corresponding power of 10 */
  83. s_short ir; /* ir = floor(r) */
  84. int retval = 1; /* assume valid number */
  85. char round; /* an additional character at the end of the string */
  86. char *p;
  87. int i;
  88. int ub_exp;
  89. int digcount;
  90. /* grab the components of the long double */
  91. expn = *U_EXP_LD(&ld);
  92. manhi = *UL_MANHI_LD(&ld);
  93. manlo = *UL_MANLO_LD(&ld);
  94. sign = expn & MSB_USHORT;
  95. expn &= 0x7fff;
  96. if (sign)
  97. fos->sign = '-';
  98. else
  99. fos->sign = ' ';
  100. if (expn==0 && manhi==0 && manlo==0) {
  101. PUT_ZERO_FOS(fos);
  102. return 1;
  103. }
  104. if (expn == 0x7fff) {
  105. fos->exp = 1; /* set a positive exponent for proper output */
  106. /* check for special cases */
  107. if (_IS_MAN_SNAN(sign, manhi, manlo)) {
  108. /* signaling NAN */
  109. STRCPY(fos->man,SNAN_STR);
  110. fos->ManLen = SNAN_STR_LEN;
  111. retval = 0;
  112. }
  113. else if (_IS_MAN_IND(sign, manhi, manlo)) {
  114. /* indefinite */
  115. STRCPY(fos->man,IND_STR);
  116. fos->ManLen = IND_STR_LEN;
  117. retval = 0;
  118. }
  119. else if (_IS_MAN_INF(sign, manhi, manlo)) {
  120. /* infinity */
  121. STRCPY(fos->man,INF_STR);
  122. fos->ManLen = INF_STR_LEN;
  123. retval = 0;
  124. }
  125. else {
  126. /* quiet NAN */
  127. STRCPY(fos->man,QNAN_STR);
  128. fos->ManLen = QNAN_STR_LEN;
  129. retval = 0;
  130. }
  131. }
  132. else {
  133. /*
  134. * Algorithm for the decoding of a valid real number x
  135. *
  136. * In the following INT(r) is the largest integer less than or
  137. * equal to r (i.e. r rounded toward -infinity). We want a result
  138. * r equal to 1 + log(x), because then x = mantissa
  139. * * 10^(INT(r)) so that .1 <= mantissa < 1. Unfortunately,
  140. * we cannot compute s exactly so we must alter the procedure
  141. * slightly. We will instead compute an estimate r of 1 +
  142. * log(x) which is always low. This will either result
  143. * in the correctly normalized number on the top of the stack
  144. * or perhaps a number which is a factor of 10 too large. We
  145. * will then check to see that if x is larger than one
  146. * and if so multiply x by 1/10.
  147. *
  148. * We will use a low precision (fixed point 24 bit) estimate
  149. * of of 1 + log base 10 of x. We have approximately .mm
  150. * * 2^hhll on the top of the stack where m, h, and l represent
  151. * hex digits, mm represents the high 2 hex digits of the
  152. * mantissa, hh represents the high 2 hex digits of the exponent,
  153. * and ll represents the low 2 hex digits of the exponent. Since
  154. * .mm is a truncated representation of the mantissa, using it
  155. * in this monotonically increasing polynomial approximation
  156. * of the logarithm will naturally give a low result. Let's
  157. * derive a formula for a lower bound r on 1 + log(x):
  158. *
  159. * .4D104D42H < log(2)=.30102999...(base 10) < .4D104D43H
  160. * .9A20H < log(4)=.60205999...(base 10) < .9A21H
  161. *
  162. * 1/2 <= .mm < 1
  163. * ==> log(.mm) >= .mm * log(4) - log(4)
  164. *
  165. * Substituting in truncated hex constants in the formula above
  166. * gives r = 1 + .4D104DH * hhll. + .9AH * .mm - .9A21H. Now
  167. * multiplication of hex digits 5 and 6 of log(2) by ll has an
  168. * insignificant effect on the first 24 bits of the result so
  169. * it will not be calculated. This gives the expression r =
  170. * 1 + .4D10H * hhll. + .4DH * .hh + .9A * .mm - .9A21H.
  171. * Finally we must add terms to our formula to subtract out the
  172. * effect of the exponent bias. We obtain the following formula:
  173. *
  174. * (implied decimal point)
  175. * < >.< >
  176. * |3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|
  177. * |1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|
  178. * + < 1 >
  179. * + < .4D10H * hhll. >
  180. * + < .00004DH * hh00. >
  181. * + < .9AH * .mm >
  182. * - < .9A21H >
  183. * - < .4D10H * 3FFEH >
  184. * - < .00004DH * 3F00H >
  185. *
  186. * ==> r = .4D10H * hhll. + .4DH * .hh + .9AH * .mm - 1343.12F4H
  187. *
  188. * The difference between the lower bound r and the upper bound
  189. * s is calculated as follows:
  190. *
  191. * .937EH < 1/ln(10)-log(1/ln(4))=.57614993...(base 10) < .937FH
  192. *
  193. * 1/2 <= .mm < 1
  194. * ==> log(.mm) <= .mm * log(4) - [1/ln(10) - log(1/ln(4))]
  195. *
  196. * so tenatively s = r + log(4) - [1/ln(10) - log(1/ln(4))],
  197. * but we must also add in terms to ensure we will have an upper
  198. * bound even after the truncation of various values. Because
  199. * log(2) * hh00. is truncated to .4D104DH * hh00. we must
  200. * add .0043H, because log(2) * ll. is truncated to .4D10H *
  201. * ll. we must add .0005H, because <mantissa> * log(4) is
  202. * truncated to .mm * .9AH we must add .009AH and .0021H.
  203. *
  204. * Thus s = r - .937EH + .9A21H + .0043H + .0005H + .009AH + .0021H
  205. * = r + .07A6H
  206. * ==> s = .4D10H * hhll. + .4DH * .hh + .9AH * .mm - 1343.0B4EH
  207. *
  208. * r is equal to 1 + log(x) more than (10000H - 7A6H) /
  209. * 10000H = 97% of the time.
  210. *
  211. * In the above formula, a u_long is use to accomodate r, and
  212. * there is an implied decimal point in the middle.
  213. */
  214. hh = expn >> 8;
  215. ll = expn & (u_short)0xff;
  216. mm = (u_short) (manhi >> 24);
  217. r = (s_long)log2hi*(s_long)expn + log2lo*hh + log4hi*mm - c;
  218. ir = (s_short)(r >> 16);
  219. /*
  220. *
  221. * We stated that we wanted to normalize x so that
  222. *
  223. * .1 <= x < 1
  224. *
  225. * This was a slight oversimplification. Actually we want a
  226. * number which when rounded to 16 significant digits is in the
  227. * desired range. To do this we must normalize x so that
  228. *
  229. * .1 - 5*10^(-18) <= x < 1 - 5*10^(-17)
  230. *
  231. * and then round.
  232. *
  233. * If we had f = INT(1+log(x)) we could multiply by 10^(-f)
  234. * to get x into the desired range. We do not quite have
  235. * f but we do have INT(r) from the last step which is equal
  236. * to f 97% of the time and 1 less than f the rest of the time.
  237. * We can multiply by 10^-[INT(r)] and if the result is greater
  238. * than 1 - 5*10^(-17) we can then multiply by 1/10. This final
  239. * result will lie in the proper range.
  240. */
  241. /* convert _LDOUBLE to _LDBL12) */
  242. *U_EXP_12(&ld12) = expn;
  243. *UL_MANHI_12(&ld12) = manhi;
  244. *UL_MANLO_12(&ld12) = manlo;
  245. *U_XT_12(&ld12) = 0;
  246. /* multiply by 10^(-ir) */
  247. __multtenpow12(&ld12,-ir,1);
  248. /* if ld12 >= 1.0 then divide by 10.0 */
  249. if (*U_EXP_12(&ld12) >= 0x3fff) {
  250. ir++;
  251. __ld12mul(&ld12,&ld12_one_tenth);
  252. }
  253. fos->exp = ir;
  254. if (output_flags & SO_FFORMAT){
  255. /* 'f' format, add exponent to ndigits */
  256. ndigits += ir;
  257. if (ndigits <= 0) {
  258. /* return 0 */
  259. PUT_ZERO_FOS(fos);
  260. return 1;
  261. }
  262. }
  263. if (ndigits > MAX_MAN_DIGITS)
  264. ndigits = MAX_MAN_DIGITS;
  265. ub_exp = *U_EXP_12(&ld12) - 0x3ffe; /* unbias exponent */
  266. *U_EXP_12(&ld12) = 0;
  267. /*
  268. * Now the mantissa has to be converted to fixed point.
  269. * Then we will use the MSB of ld12 for generating
  270. * the decimal digits. The next 11 bytes will hold
  271. * the mantissa (after it has been converted to
  272. * fixed point).
  273. */
  274. for (i=0;i<8;i++)
  275. __shl_12(&ld12); /* make space for an extra byte,
  276. in case we shift right later */
  277. if (ub_exp < 0) {
  278. int shift_count = (-ub_exp) & 0xff;
  279. for (;shift_count>0;shift_count--)
  280. __shr_12(&ld12);
  281. }
  282. p = fos->man;
  283. for(digcount=ndigits+1;digcount>0;digcount--) {
  284. tmp12 = ld12;
  285. __shl_12(&ld12);
  286. __shl_12(&ld12);
  287. __add_12(&ld12,&tmp12);
  288. __shl_12(&ld12); /* ld12 *= 10 */
  289. /* Now we have the first decimal digit in the msbyte of exponent */
  290. *p++ = (char) (*UCHAR_12(&ld12,11) + '0');
  291. *UCHAR_12(&ld12,11) = 0;
  292. }
  293. round = *(--p);
  294. p--; /* p points now to the last character of the string
  295. excluding the rounding digit */
  296. if (round >= '5') {
  297. /* look for a non-9 digit starting from the end of string */
  298. for (;p>=fos->man && *p=='9';p--) {
  299. *p = '0';
  300. }
  301. if (p < fos->man){
  302. p++;
  303. fos->exp ++;
  304. }
  305. (*p)++;
  306. }
  307. else {
  308. /* remove zeros */
  309. for (;p>=fos->man && *p=='0';p--);
  310. if (p < fos->man) {
  311. /* return 0 */
  312. PUT_ZERO_FOS(fos);
  313. return 1;
  314. }
  315. }
  316. fos->ManLen = (char) (p - fos->man + 1);
  317. fos->man[fos->ManLen] = '\0';
  318. }
  319. return retval;
  320. }