home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / fcvt.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  7KB  |  218 lines

  1. /***
  2. *fcvt.c - convert floating point value to string
  3. *
  4. *       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       Converts a floating point value to a string.
  8. *
  9. *******************************************************************************/
  10.  
  11. #include <cruntime.h>
  12. #include <fltintrn.h>
  13. #include <cvt.h>
  14. #include <mtdll.h>
  15. #include <stdlib.h>
  16. #include <dbgint.h>
  17.  
  18. /*
  19.  * The static character array buf[CVTBUFSIZE] is used by the _fpcvt routine
  20.  * (the workhorse for _ecvt and _fcvt) for storage of its output.  The routine
  21.  * gcvt expects the user to have set up their own storage.  CVTBUFSIZE is set
  22.  * large enough to accomodate the largest double precision number plus 40
  23.  * decimal places (even though you only have 16 digits of accuracy in a
  24.  * double precision IEEE number, the user may ask for more to effect 0
  25.  * padding; but there has to be a limit somewhere).
  26.  */
  27.  
  28. /*
  29.  * define a maximum size for the conversion buffer.  It should be at least
  30.  * as long as the number of digits in the largest double precision value
  31.  * (?.?e308 in IEEE arithmetic).  We will use the same size buffer as is
  32.  * used in the printf support routine (_output)
  33.  */
  34.  
  35. #ifdef _MT
  36. char * __cdecl _fpcvt(STRFLT, int, int *, int *);
  37. #else  /* _MT */
  38. static char * __cdecl _fpcvt(STRFLT, int, int *, int *);
  39. static char buf[CVTBUFSIZE];
  40. #endif  /* _MT */
  41.  
  42. /***
  43. *char *_fcvt(value, ndec, decpr, sign) - convert floating point to char string
  44. *
  45. *Purpose:
  46. *       _fcvt like _ecvt converts the value to a null terminated
  47. *       string of ASCII digits, and returns a pointer to the
  48. *       result.  The routine prepares data for Fortran F-format
  49. *       output with the number of digits following the decimal
  50. *       point specified by ndec.  The position of the decimal
  51. *       point relative to the beginning of the string is returned
  52. *       indirectly through decpt.  The correct digit for Fortran
  53. *       F-format is rounded.
  54. *       NOTE - to avoid the possibility of generating floating
  55. *       point instructions in this code we fool the compiler
  56. *       about the type of the 'value' parameter using a struct.
  57. *       This is OK since all we do is pass it off as a
  58. *       parameter.
  59. *
  60. *Entry:
  61. *       double value - number to be converted
  62. *       int ndec - number of digits after decimal point
  63. *
  64. *Exit:
  65. *       returns pointer to the character string representation of value.
  66. *       also, the output is written into the static char array buf.
  67. *       int *decpt - pointer to int with pos. of dec. point
  68. *       int *sign - pointer to int with sign (0 = pos, non-0 = neg)
  69. *
  70. *Exceptions:
  71. *
  72. *******************************************************************************/
  73.  
  74. char * __cdecl _fcvt (
  75.         double value,
  76.         int ndec,
  77.         int *decpt,
  78.         int *sign
  79.         )
  80. {
  81.         REG1 STRFLT pflt;
  82.  
  83. #ifdef _MT
  84.         struct _strflt strfltstruct;
  85.         char resultstring[21];
  86.  
  87.         /* ok to take address of stack struct here; fltout2 knows to use ss */
  88.         pflt = _fltout2( value, &strfltstruct, resultstring );
  89.  
  90.  
  91. #else  /* _MT */
  92.         pflt = _fltout( value );
  93. #endif  /* _MT */
  94.  
  95.         return( _fpcvt( pflt, pflt->decpt + ndec, decpt, sign ) );
  96. }
  97.  
  98.  
  99. /***
  100. *char *_ecvt( value, ndigit, decpt, sign ) - convert floating point to string
  101. *
  102. *Purpose:
  103. *       _ecvt converts value to a null terminated string of
  104. *       ASCII digits, and returns a pointer to the result.
  105. *       The position of the decimal point relative to the
  106. *       begining of the string is stored indirectly through
  107. *       decpt, where negative means to the left of the returned
  108. *       digits.  If the sign of the result is negative, the
  109. *       word pointed to by sign is non zero, otherwise it is
  110. *       zero.  The low order digit is rounded.
  111. *
  112. *Entry:
  113. *       double value - number to be converted
  114. *       int ndigit - number of digits after decimal point
  115. *
  116. *Exit:
  117. *       returns pointer to the character representation of value.
  118. *       also the output is written into the statuc char array buf.
  119. *       int *decpt - pointer to int with position of decimal point
  120. *       int *sign - pointer to int with sign in it (0 = pos, non-0 = neg)
  121. *
  122. *Exceptions:
  123. *
  124. *******************************************************************************/
  125.  
  126. char * __cdecl _ecvt (
  127.         double value,
  128.         int ndigit,
  129.         int *decpt,
  130.         int *sign
  131.         )
  132. {
  133.  
  134.         char *retbuf;
  135.  
  136. #ifdef _MT
  137.         REG1 STRFLT pflt;
  138.  
  139.         struct _strflt strfltstruct;        /* temporary buffers */
  140.         char resultstring[21];
  141.  
  142.         /* ok to take address of stack struct here; fltout2 knows to use ss */
  143.         pflt = _fltout2( value, &strfltstruct, resultstring );
  144.  
  145.         retbuf = _fpcvt( pflt, ndigit, decpt, sign );
  146.  
  147. #else  /* _MT */
  148.         retbuf = _fpcvt( _fltout(value), ndigit, decpt, sign );
  149. #endif  /* _MT */
  150.  
  151.         /* _fptostr() occasionally returns an extra character in the buffer ... */
  152.  
  153.         if (retbuf[ndigit])
  154.                 retbuf[ndigit] = '\0';
  155.         return( retbuf );
  156. }
  157.  
  158.  
  159. /***
  160. *char *_fpcvt() - gets final string and sets decpt and sign     [STATIC]
  161. *
  162. *Purpose:
  163. *       This is a small common routine used by [ef]cvt.  It calls fptostr
  164. *       to get the final string and sets the decpt and sign indicators.
  165. *
  166. *Entry:
  167. *
  168. *Exit:
  169. *
  170. *Exceptions:
  171. *
  172. *******************************************************************************/
  173.  
  174. #ifdef _MT
  175. char * __cdecl _fpcvt (
  176. #else  /* _MT */
  177. static char * __cdecl _fpcvt (
  178. #endif  /* _MT */
  179.         REG2 STRFLT pflt,
  180.         REG3 int digits,
  181.         int *decpt,
  182.         int *sign
  183.         )
  184. {
  185.  
  186. #ifdef _MT
  187.  
  188.         /* use a per-thread buffer */
  189.  
  190.         char *buf;
  191.  
  192.         _ptiddata ptd;
  193.  
  194.         ptd = _getptd();
  195.         if ( ptd->_cvtbuf == NULL )
  196.                 if ( (ptd->_cvtbuf = _malloc_crt(CVTBUFSIZE)) == NULL )
  197.                         return(NULL);
  198.         buf = ptd->_cvtbuf;
  199.  
  200. #endif  /* _MT */
  201.  
  202.  
  203.         /* make sure we don't overflow the buffer size.  If the user asks for
  204.          * more digits than the buffer can handle, truncate it to the maximum
  205.          * size allowed in the buffer.  The maximum size is CVTBUFSIZE - 2
  206.          * since we useone character for overflow and one for the terminating
  207.          * null character.
  208.          */
  209.  
  210.         _fptostr(buf, (digits > CVTBUFSIZE - 2) ? CVTBUFSIZE - 2 : digits, pflt);
  211.  
  212.         /* set the sign flag and decimal point position */
  213.  
  214.         *sign = (pflt->sign == '-') ? 1 : 0;
  215.         *decpt = pflt->decpt;
  216.         return(buf);
  217. }
  218.