floatLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:18k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* floatLib.c - floating-point formatting and scanning library */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02f,19oct01,dcb  Fix the routine title line to match the coding conventions.
  8. 02e,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  9. 02d,30jul96,dbt  fixed floatScan to avoid loose of precision (SPR #3829).
  10.    Updated copyright.
  11. 02c,01dec94,ism  fixed alt 'g' format bug.  Added in-line docs.
  12. 02b,06oct94,ism  fixed %.XXg outputting more than XX sig figs (SPR#3695)
  13. 02a,27jan93,jdi  documentation cleanup for 5.1; fixed SPR 1399.
  14. 01z,30jul92,kdl  Restored 01w changes (clobbered by 01x); removed fpTypeGet()
  15.  and isInf, isNan, & isZero macros.
  16. 01y,30jul92,rrr  Removed decl of DOUBLE (now in mathLibP.h)
  17. 01x,30jul92,smb  (Accidental checkin.)
  18. 01w,30jul92,kdl  Significantly reworked for new ansi fio; moved frexp(), 
  19.    +jcf  ldexp(), modf() to src/libc/math; moved DOUBLE union 
  20.  definition to mathP.h; removed special handling for i960.
  21. 01v,18jul92,smb  Changed errno.h to errnoLib.h.
  22. 01u,13jul92,smb  frexp, ldexp, modf now in libc for the SPARC (temporary change)
  23. 01t,26may92,rrr  the tree shuffle
  24. 01s,04mar92,wmd  placed declaration of atof() outside of 960 conditional,
  25.  included string.h.
  26. 01r,10dec91,gae  added includes for ANSI.
  27. 01q,28oct91,wmd  added in type casting for *pCh in floatScan as per Intel mods.
  28. 01p,04oct91,rrr  passed through the ansification filter
  29.                   -changed functions to ansi style
  30.   -changed includes to have absolute path from h/
  31.   -fixed #else and #endif
  32.   -changed VOID to void
  33.   -changed copyright notice
  34. 01o,09jun91,del  integration of mods by intel for interfacing to gnu960
  35.  libraries and fix bugs from 01m.
  36. 01n,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  37.  doc review by dnw.
  38. 01m,25mar91,del  interfaces to gnu960 flt. pt. libraries for I960CA
  39. 01l,07feb91,jaa  documentation cleanup.
  40. 01k,23aug90,elr  Documentation
  41. 01j,01aug90,dnw  fixed bug in floatScan scanning <nn>e<nn> format numbers.
  42.  changed floatFormat to take pVaList instead of vaList.
  43. 01i,04jun90,dnw  changed floatFormat to take a vararg va_list instead of a
  44.    double arg, so that fioLib can be free of all flt pt refs.
  45.  replaced floatAtoF with new routine floatScan, written
  46.    from scratch, with our own algorithm for scanning flt pt
  47.    numbers, designed to work with scanField() in fioLib.
  48.  fixed bug incorrectly scanning large numbers that are too big.
  49.  fixed documentation.
  50.  make ecvtb, fcvtb, gcvtb be "no manual".
  51. 01h,07mar90,jdi  documentation cleanup.
  52. 01g,20apr89,dab  fixed precision bug in cvtb().
  53.  documentation touchup in fcvtb() and cvtb().
  54. 01f,05jun88,dnw  changed name from fltLib to floatLib.
  55. 01e,30may88,dnw  changed to v4 names.
  56. 01d,28may88,dnw  changed atof() to fltAtoF().
  57. 01c,17mar88,gae  added 'E' and 'G' format specifiers.
  58. 01b,05nov87,jlf  documentation
  59. 01a,01aug87,gae  written/extracted from fioLib.c.
  60. */
  61. /*
  62. DESCRIPTION
  63. This library provides the floating-point I/O formatting and scanning
  64. support routines.
  65. The floating-point formatting and scanning support routines are not
  66. directly callable; they are connected to call-outs in the printf()/scanf()
  67. family of functions in fioLib.  This is done dynamically by the routine
  68. floatInit(), which is called by the root task, usrRoot(), in usrConfig.c
  69. when the configuration macro INCLUDE_FLOATING_POINT is defined.
  70. If this option is omitted (i.e., floatInit() is not called), floating-point
  71. format specifications in printf() and sscanf() are not supported.
  72. INCLUDE FILES: math.h
  73. SEE ALSO: fioLib
  74. */
  75. #include "vxWorks.h"
  76. #include "vwModNum.h"
  77. #include "fioLib.h"
  78. #include "string.h"
  79. #include "stdlib.h"
  80. #include "ctype.h"
  81. #include "string.h"
  82. #include "errnoLib.h"
  83. #include "math.h"
  84. #include "limits.h"
  85. #include "stdarg.h"
  86. #include "fioLib.h"
  87. #include "private/floatioP.h"
  88. #include "private/mathP.h"
  89. /* macros */
  90. #define to_digit(c) ((c) - '0')
  91. #define is_digit(c) ((unsigned)to_digit(c) <= 9)
  92. #define to_char(n) ((n) + '0')
  93. /* forward static functions */
  94. LOCAL int  floatFormat (va_list *pVaList, int precision, BOOL doAlt, 
  95.              int fmtSym, BOOL *pDoSign, char *pBufStart, 
  96.              char *pBufEnd);
  97. LOCAL BOOL  floatScan (int *pReturn, int returnSpec, int fieldwidth,
  98.            FUNCPTR getRtn, int getArg, int *pCh, int *pNchars);
  99. LOCAL int  cvt (double number, int prec, BOOL doAlt, int fmtch,
  100.              BOOL *pDoSign, char *startp, char *endp);
  101. LOCAL char * exponentCvt (char *p, int exp, int fmtch);
  102. LOCAL char * roundCvt (double fract, int *exp, char *start, char *end, 
  103.   char ch, BOOL *pDoSign);
  104. LOCAL int floatFpTypeGet ( double v, double * r);
  105. /*******************************************************************************
  106. *
  107. * floatInit - initialize floating-point I/O support
  108. *
  109. * This routine must be called if floating-point format specifications are
  110. * to be supported by the printf()/scanf() family of routines.
  111. * If the configuration macro INCLUDE_FLOATING_POINT is defined, it is called
  112. * by the root task, usrRoot(), in usrConfig.c.
  113. *
  114. * RETURNS: N/A
  115. */
  116. void floatInit (void)
  117.     {
  118.     fioFltInstall ((FUNCPTR)floatFormat, (FUNCPTR)floatScan);
  119.     }
  120. /*******************************************************************************
  121. *
  122. * floatFormat - format arg for output
  123. *
  124. * This routine converts from a floating-point value to an ASCII representation.
  125. * The <fmtSym> parameter indicates the format type desired; the actual work
  126. * is done in cvt.
  127. *
  128. * RETURNS: number of characters placed in buffer
  129. */
  130. LOCAL int floatFormat 
  131.     (
  132.     va_list * pVaList, /* vararg list */
  133.     int precision, /* precision */
  134.     BOOL doAlt,  /* doAlt boolean */
  135.     int fmtSym, /* format symbol */
  136.     BOOL * pDoSign,  /* where to fill in doSign result */
  137.     char * pBufStart, /* buffer start */
  138.     char * pBufEnd /* buffer end */
  139.     )
  140.     {
  141.     double dbl = (double) va_arg (*pVaList, double);
  142.     *pDoSign = FALSE; /* assume no sign needed */
  143.     if (isInf(dbl))  /* infinite? */
  144. {
  145. strcpy (pBufStart, "Inf"); /* fill in the string */
  146. if (dbl < 0.0) /* less than 0.0 */
  147.     *pDoSign = TRUE; /* we need a sign */
  148. return (-3); /* length will be three */
  149. }
  150.     if (isNan(dbl))  /* not a number? */
  151. {
  152. strcpy (pBufStart, "NaN"); /* fill in the string */
  153. return (-3); /* length will be three */
  154. }
  155.     return (cvt (dbl, precision, doAlt, fmtSym, pDoSign, pBufStart, pBufEnd));
  156.     }
  157. /******************************************************************************
  158. * cvt - helper function for floatFormat
  159. * RETURNS: 
  160. */
  161. LOCAL int cvt
  162.     (
  163.     double number,
  164.     FAST int prec,
  165.     BOOL doAlt,
  166.     int fmtch,
  167.     BOOL * pDoSign,
  168.     char * startp,
  169.     char * endp
  170.     )
  171.     {
  172.     FAST char * p;
  173.     FAST char * t;
  174.     FAST double fract;
  175.     int  dotrim;
  176.     int  expcnt;
  177.     int  gformat;
  178. int nonZeroInt=FALSE;
  179.     double  integer;
  180.     double tmp;
  181.     dotrim = expcnt = gformat = 0;
  182.     if (number < 0) 
  183. {
  184. number = -number;
  185. *pDoSign = TRUE;
  186. }
  187.     else
  188. *pDoSign = FALSE;
  189.     fract = modf(number, &integer);
  190. if(integer!=(double)0.0)
  191. nonZeroInt=TRUE;
  192.     t = ++startp; /* get an extra slot for rounding. */
  193.     /* get integer portion of number; put into the end of the buffer; the
  194.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  195.      */
  196.     for (p = endp - 1; integer; ++expcnt) 
  197. {
  198. tmp  = modf(integer / 10, &integer);
  199. *p-- = to_char((int)((tmp + .01) * 10));
  200. }
  201.     switch (fmtch) 
  202. {
  203. case 'f':
  204. /* reverse integer into beginning of buffer */
  205. if (expcnt)
  206.     for (; ++p < endp; *t++ = *p);
  207. else
  208.     *t++ = '0';
  209. /* if precision required or alternate flag set, add in a
  210.  * decimal point.
  211.  */
  212. if (prec || doAlt)
  213.     *t++ = '.';
  214. /* if requires more precision and some fraction left */
  215. if (fract) 
  216.     {
  217.     if (prec)
  218. do 
  219.     {
  220.     fract = modf(fract * 10, &tmp);
  221.     *t++  = to_char((int)tmp);
  222.     } while (--prec && fract);
  223.     if (fract)
  224. startp = roundCvt (fract, (int *)NULL, startp, t - 1,
  225.        (char)0, pDoSign);
  226.     }
  227. for (; prec--; *t++ = '0')
  228.     ;
  229. break;
  230. case 'e':
  231. case 'E':
  232. eformat: if (expcnt) 
  233.     {
  234.     *t++ = *++p;
  235.     if (prec || doAlt)
  236. *t++ = '.';
  237.     /* if requires more precision and some integer left */
  238.     for (; prec && ++p < endp; --prec)
  239. *t++ = *p;
  240.     /* if done precision and more of the integer component,
  241.      * round using it; adjust fract so we don't re-round
  242.      * later.
  243.      */
  244.     if (!prec && ++p < endp)
  245. {
  246. fract  = 0;
  247. startp = roundCvt((double)0, &expcnt, startp, t - 1, *p,
  248.        pDoSign);
  249. }
  250.     --expcnt; /* adjust expcnt for dig. in front of decimal */
  251.     }
  252. /* until first fractional digit, decrement exponent */
  253. else if (fract) 
  254.     {
  255.     /* adjust expcnt for digit in front of decimal */
  256.     for (expcnt = -1;; --expcnt) 
  257. {
  258. fract = modf(fract * 10, &tmp);
  259. if (tmp)
  260.     break;
  261. }
  262.     *t++ = to_char((int)tmp);
  263.     if (prec || doAlt)
  264. *t++ = '.';
  265.     }
  266. else 
  267.     {
  268.     *t++ = '0';
  269.     if (prec || doAlt)
  270. *t++ = '.';
  271.     }
  272. /* if requires more precision and some fraction left */
  273. if (fract) 
  274.     {
  275.     if (prec)
  276. do 
  277.     {
  278.     fract = modf(fract * 10, &tmp);
  279.     *t++ = to_char((int)tmp);
  280.     } while (--prec && fract);
  281.     if (fract)
  282. startp = roundCvt(fract, &expcnt, startp, t - 1,(char)0,
  283.           pDoSign);
  284.     }
  285. for (; prec--; *t++ = '0') /* if requires more precision */
  286.     ;
  287. /* unless alternate flag, trim any g/G format trailing 0's */
  288. if (gformat && !doAlt) 
  289.     {
  290.     while (t > startp && *--t == '0')
  291. ;
  292.     if (*t == '.')
  293. --t;
  294.     ++t;
  295.     }
  296. t = exponentCvt (t, expcnt, fmtch);
  297. break;
  298. case 'g':
  299. case 'G':
  300. /* a precision of 0 is treated as a precision of 1. */
  301. if (!prec)
  302.     ++prec;
  303. /*
  304.  * ``The style used depends on the value converted; style e
  305.  * will be used only if the exponent resulting from the
  306.  * conversion is less than -4 or greater than the precision.''
  307.  * -- ANSI X3J11
  308.  */
  309. if (expcnt > prec || !expcnt && fract && fract < .0001) 
  310.     {
  311.     /*
  312.      * g/G format counts "significant digits, not digits of
  313.      * precision; for the e/E format, this just causes an
  314.      * off-by-one problem, i.e. g/G considers the digit
  315.      * before the decimal point significant and e/E doesn't
  316.      * count it as precision.
  317.      */
  318.     --prec;
  319.     fmtch  -= 2; /* G->E, g->e */
  320.     gformat = 1;
  321.     goto eformat;
  322.     }
  323. /*
  324.  * reverse integer into beginning of buffer,
  325.  * note, decrement precision
  326.  */
  327. if (expcnt)
  328.     for (; ++p < endp; *t++ = *p, --prec)
  329. ;
  330. else
  331.     *t++ = '0';
  332. /*
  333.  * if precision required or alternate flag set, add in a
  334.  * decimal point.  If no digits yet, add in leading 0.
  335.  */
  336. if (prec || doAlt) 
  337.     {
  338.     dotrim = 1;
  339.     *t++ = '.';
  340.     }
  341. else
  342.     dotrim = 0;
  343. /* if requires more precision and some fraction left */
  344. if (fract) 
  345.     {
  346.     if (prec) 
  347. {
  348. /*
  349.  * If there is a zero integer portion, so we can't count any
  350.              * of the leading zeros as significant.  Roll 'em on out until
  351.  * we get to the first non-zero one.
  352.  */
  353. if (!nonZeroInt)
  354. {
  355. do 
  356.      {
  357.      fract = modf(fract * 10, &tmp);
  358.      *t++ = to_char((int)tmp);
  359.      } while(!tmp);
  360. prec--;
  361. }
  362. /*
  363.              * Now add on a number of digits equal to our precision.
  364.              */
  365. while (prec && fract) 
  366.     {
  367.     fract = modf(fract * 10, &tmp);
  368.     *t++ = to_char((int)tmp);
  369. prec--;
  370.     }
  371. }
  372.     if (fract)
  373. startp = roundCvt (fract, (int *)NULL, startp, t - 1,
  374.            (char)0, pDoSign);
  375.     }
  376. /* alternate format, adds 0's for precision, else trim 0's */
  377. if (doAlt)
  378.      for (; prec--; *t++ = '0')
  379.          ;
  380. else if (dotrim) 
  381.     {
  382.     while (t > startp && *--t == '0')
  383. ;
  384.     if (*t != '.')
  385. ++t;
  386.     }
  387. default :
  388. break;
  389. }
  390.     return (t - startp);
  391.     }
  392. /******************************************************************************
  393. *
  394. * roundCvt - helper function for floatFormat
  395. * RETURNS: 
  396. */
  397. LOCAL char *roundCvt
  398.     (
  399.     double fract,
  400.     int * exp,
  401.     FAST char * start,
  402.     FAST char * end,
  403.     char  ch,
  404.     BOOL * pDoSign
  405.     )
  406.     {
  407.     double tmp;
  408.     if (fract)
  409. (void)modf(fract * 10, &tmp);
  410.     else
  411. tmp = to_digit(ch);
  412.     if (tmp > 4)
  413. {
  414. for (;; --end) 
  415.     {
  416.     if (*end == '.')
  417.     --end;
  418.     if (++*end <= '9')
  419.     break;
  420.     *end = '0';
  421.     if (end == start) 
  422. {
  423. if (exp) 
  424.     { /* e/E; increment exponent */
  425.     *end = '1';
  426.     ++*exp;
  427.     }
  428. else 
  429.     { /* f; add extra digit */
  430.     *--end = '1';
  431.     --start;
  432.     }
  433. break;
  434. }
  435.     }
  436. }
  437.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  438.     else if (*pDoSign)
  439. for (;; --end) 
  440.     {
  441.     if (*end == '.')
  442. --end;
  443.     if (*end != '0')
  444. break;
  445.     if (end == start)
  446. *pDoSign = FALSE;
  447.     }
  448.     return (start);
  449.     }
  450. /******************************************************************************
  451. *
  452. * exponentCvt - helper function for floatFormat
  453. * RETURNS: 
  454. */
  455. LOCAL char *exponentCvt
  456.     (
  457.     FAST char * p,
  458.     FAST int  exp,
  459.     int  fmtch
  460.     )
  461.     {
  462.     FAST char *t;
  463.     char expbuf[MAXEXP];
  464.     *p++ = fmtch;
  465.     if (exp < 0) 
  466. {
  467. exp = -exp;
  468. *p++ = '-';
  469. }
  470.     else
  471. *p++ = '+';
  472.     t = expbuf + MAXEXP;
  473.     if (exp > 9) 
  474. {
  475. do 
  476.     {
  477.     *--t = to_char(exp % 10);
  478.     } while ((exp /= 10) > 9);
  479. *--t = to_char(exp);
  480. for (; t < expbuf + MAXEXP; *p++ = *t++)
  481.     ;
  482. }
  483.     else 
  484. {
  485. *p++ = '0';
  486. *p++ = to_char(exp);
  487. }
  488.     return (p);
  489.     }
  490. /*******************************************************************************
  491. *
  492. * floatScan - scan ASCII input to a floating-point number
  493. *
  494. * This routine scans the ASCII input into a floating-point number.
  495. *
  496. * [+-]<digs>.<digs>e[+-]<digs>
  497. *
  498. * RETURNS: TRUE if successful, FALSE if unsuccessful
  499. */
  500. LOCAL BOOL floatScan
  501.     (
  502.     FAST int *  pReturn,
  503.     int         returnSpec,     /* 0, 'l', 'L' */
  504.     int         fieldwidth,
  505.     FAST FUNCPTR getRtn,
  506.     FAST int    getArg,
  507.     int *       pCh,
  508.     int *       pNchars
  509.     )
  510.     {
  511. #define DBL_DIG 16 /* float.h */
  512. #define GET_CHAR(ch, ix) ((ix)++, (ch) = getRtn (getArg))
  513.     static double power10 [] =
  514.     {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8};
  515.     static double posExpPower10 [] =
  516.     {1e1, 1e2, 1e4, 1e8, 1e16, 1e32, 1e64, 1e128, 1e256, 0};
  517.     FAST int ch   = *pCh; /* current char */
  518.     FAST int ix   = 0; /* number of chars consumed */
  519.     FAST long long1   = 0; /* 1st part of integer representation */
  520.     FAST long long2   = 0; /* 2nd part of integer representation */
  521.     int ndigs1   = 0; /* num of digits in long1 */
  522.     int ndigs2   = 0; /* num of digits in long2 */
  523.     int ndigsPrec = 0; /* num of digits of precision total */
  524.     BOOL fracPart  = FALSE; /* TRUE = doing digits after '.' */
  525.     int ndigsFrac = 0; /* number of digits after '.' */
  526.     int exp   = 0; /* exponent */
  527.     double num; /* double representation of number */
  528.     BOOL negnum = FALSE; /* number is negative */
  529.     BOOL negexp = FALSE; /* exponent is negative */
  530.     double * pExpPower10; /* current exponent bit multiplier */
  531.     /* check for sign */
  532.     if (ix < fieldwidth)
  533. {
  534. if ((negnum = ((char)ch == '-')) || ((char)ch == '+'))
  535.     GET_CHAR (ch, ix);
  536. }
  537.     /* scan integer and fraction parts */
  538.     for (; (ch != EOF) && (ix < fieldwidth); GET_CHAR (ch, ix))
  539. {
  540. if (!fracPart && ch == '.')
  541.     {
  542.     fracPart = TRUE;
  543.     continue;
  544.     }
  545. if ((ch < '0') || (ch > '9'))
  546.     break;
  547. ch -= '0'; /* turn ch into digit */
  548. if (fracPart) /* count digits after '.' */
  549.     ndigsFrac++;
  550. if ((ndigsPrec != 0) || (ch != 0)) /* skip leading 0s */
  551.     {
  552.     ndigsPrec++;
  553.     /* check if another digit will fit in long1 */
  554.     if (long1 < ((INT_MAX - 9) / 10))
  555. {
  556. long1 = 10 * long1 + ch;
  557. ndigs1++;
  558. }
  559.     else if (ndigsPrec <= DBL_DIG)
  560. {
  561. long2 = 10 * long2 + ch;
  562. ndigs2++;
  563. }
  564.     }
  565. }
  566.     /* scan for explicit exponent */
  567.     if ((ix < fieldwidth) && (ch == 'e' || ch == 'E'))
  568. {
  569. GET_CHAR (ch, ix);
  570. /* skip over sign */
  571. if (ix < fieldwidth)
  572.     {
  573.     if ((negexp = (ch == '-')) || (ch == '+'))
  574. GET_CHAR (ch, ix);
  575.     }
  576. for (; (ch != EOF) && (ix < fieldwidth); GET_CHAR (ch, ix))
  577.     {
  578.     if ((ch < '0') || (ch > '9'))
  579. break;
  580.     exp = 10 * exp + (ch - '0');
  581.     }
  582. }
  583.     /* check that we scanned at least one character */
  584.     if (ix == 0)
  585. return (FALSE);
  586.     /* put significant digits into double representation */
  587.     num = long1;
  588.     if (ndigs2 != 0)
  589. num = num * power10 [ndigs2] + long2;
  590.     /* apply exponent to number; total effective exponent =
  591.      *   + number of digits of precision that were scanned but not
  592.      *     represented in the number (ndigsPrec - ndigs1 - ndigs2)
  593.      *   - number of digits scanned after the '.' (ndigsFrac)
  594.      *   + the scanned explicit exponent
  595.      */
  596.     exp = (ndigsPrec - ndigs1 - ndigs2) - ndigsFrac + (negexp ? -exp : exp);
  597.     if ((negexp = (exp < 0)))
  598. exp = -exp;
  599.     pExpPower10 = posExpPower10;
  600.     while ((exp != 0) && (*pExpPower10 != 0))
  601. {
  602. if (exp & 1)
  603.     {
  604.     if (negexp) 
  605.      num /= *pExpPower10;
  606.     else
  607.      num *= *pExpPower10;
  608.     }
  609. exp >>= 1;
  610. pExpPower10++;
  611. }
  612.     if (exp != 0)
  613. {
  614. /* exponent too big */
  615. if (negexp)
  616.     num = 0;
  617. else
  618.     {
  619.     /* Infinity */
  620.     ((DOUBLE *) &num)->ldat.l1 = 0x7ff00000;
  621.     ((DOUBLE *) &num)->ldat.l2 = 0;
  622.     }
  623. }
  624.     /* return value to caller */
  625.     if (negnum)
  626. num = -num;
  627.     if (pReturn != NULL)
  628. {
  629. switch (returnSpec)
  630.     {
  631.     case 'l': * (double *) pReturn = num; break;
  632.     default:  * (float *) pReturn = num; break;
  633.     }
  634. }
  635.     *pCh = ch;
  636.     *pNchars += ix;
  637.     return (ix != 0);
  638.     }