home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / GCC 1.37.1r14 / usr / lib / stdlib / strtod.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-12  |  4.7 KB  |  147 lines  |  [TEXT/R*ch]

  1. /*  File   : strtod.c
  2.     Author : Based on str2dbl.c by Richard A. O'Keefe @ Quintus Computer Systems, Inc.
  3.     Updated: 12-11-93 by Jonathan Kimmitt
  4.     Defines: double strtod(char *str, char**ptr)
  5. */
  6.  
  7. /*  This is an implementation of the strtod() function based on str2dbl()
  8.     by the above author but with dependence on external libraries removed,
  9.     and certain simplifications.
  10.     
  11.     From the author:
  12.     
  13.     There are two reasons why this should be provided to the net:
  14.     (a) some UNIX systems do not yet have strtod(), or do not have it
  15.         available in the BSD "universe" (but they do have atof()).
  16.     (b) some of the UNIX systems that *do* have it get it wrong.
  17.        (some crash with large arguments, some assign the wrong *ptr value).
  18.     There is a reason why *we* are providing it: we need a correct version
  19.     of strtod(), and if we give this one away maybe someone will look for
  20.     mistakes in it and fix them for us (:-).
  21. */
  22.     
  23. /*  The following constants are machine-specific.  MD{MIN,MAX}EXPT are
  24.     integers and MD{MIN,MAX}FRAC are strings such that
  25.        0.${MDMAXFRAC}e${MDMAXEXPT} is the largest representable double,
  26.        0.${MDMINFRAC}e${MDMINEXPT} is the smallest representable +ve double
  27.     MD{MIN,MAX}FRAC must not have any trailing zeros.
  28.     The values here are for IEEE-754 64-bit floats.
  29.     It is not perfectly clear to me whether an IEEE infinity should be
  30.     returned for overflow, nor what a portable way of writing one is,
  31.     so HUGE is just 0.MAXFRAC*10**MAXEXPT (this seems still to be the
  32.     UNIX convention).
  33.  
  34.     I do know about <values.h>, but the whole point of this file is that
  35.     we can't always trust that stuff to be there or to be correct.
  36. */
  37.  
  38. #include <errno.h>
  39. #include <stdlib.h>
  40. #include <math.h>
  41.  
  42. short __D_INF[]            = { 0x7FF0, 0x0000, 0x0000, 0x0000 };
  43.  
  44. #undef HUGE_VAL
  45. #define HUGE_VAL (*((double *) __D_INF))
  46.  
  47. #define MDMINEXPT -323
  48. #define ZERO 0.0
  49. #define MDMAXEXPT 309
  50. #define MDMINFRAC 0.494065645841246544
  51. #define MDMAXFRAC 0.17976931348623147
  52.  
  53. extern int     errno;
  54.  
  55. #if __STDC__
  56. double strtod (const char *sp, char **ptr)
  57. #else
  58. double strtod(sp, ptr)
  59.     const char *sp;
  60.     char **ptr;
  61. #endif
  62.     {
  63.        int sign = 1;
  64.         int scale = 0;
  65.         int dotseen = 0;
  66.        int esign = 1;
  67.        int expt = 0;
  68.        const char *save;
  69.        register int c;
  70.        double fp_tot = 0.0;
  71.        double fp_scale = 1.0;
  72.        if (ptr) *ptr = (char *)sp;
  73.        while (*sp == ' ') sp++;
  74.        if (*sp == '-') sign -= 2, sp++;
  75.        for (save = sp; c = *sp; sp++)
  76.            if (c == '.') {
  77.                if (dotseen) break;
  78.                dotseen++;
  79.            } else
  80.            if ((unsigned)(c-'0') > (unsigned)('9'-'0')) {
  81.                break;
  82.            } else
  83.            if ((c == '0') && (fp_tot == 0.0)) {
  84.                    /* No non-zero digits seen yet */
  85.                    /* If a . has been seen, scale must be adjusted */
  86.                    if (dotseen) scale--;
  87.            } else {
  88.                /* This is a non leading zero digit, so we want to keep it */
  89.                fp_tot += (fp_scale *= 0.1)*(c-'0');
  90.                /* If it precedes a ., scale must be adjusted */
  91.                if (!dotseen) scale++;
  92.            }
  93.        if (sp == save) {
  94.            errno = EDOM;               /* what should this be? */
  95.            return ZERO;
  96.        }
  97.        
  98.        save = sp;
  99.        do {
  100.            c = *sp++;
  101.            if (c != 'e' && c != 'E') break;
  102.            c = *sp++;
  103.            if (c == '-') esign -= 2, c = *sp++; else
  104.            if (c == '+' || c == ' ') c = *sp++;
  105.            if ((unsigned)(c-'0') > (unsigned)('9'-'0')) break;
  106.            while (c == '0') c = *sp++;
  107.            for (; (unsigned)(c-'0') <= (unsigned)('9'-'0'); c = *sp++)
  108.                expt = expt*10 + c-'0';     
  109.            if (esign < 0) expt = -expt;
  110.            save = sp-1;
  111.        } while (0);
  112.        if (ptr) *ptr = (char *)save;
  113.        expt += scale;
  114.        /*  Now the number is sign*0.fraction*10**expt  */
  115.        errno = ERANGE;
  116.        if (expt > MDMAXEXPT) {
  117.            return HUGE*sign;
  118.        } else
  119.        if (expt == MDMAXEXPT) {
  120.            if (fp_tot > MDMAXFRAC) return HUGE*sign;
  121.        } else
  122.        if (expt < MDMINEXPT) {
  123.            return ZERO*sign;
  124.        } else
  125.        if (expt == MDMINEXPT) {
  126.            if (fp_tot < MDMINFRAC) return ZERO*sign;
  127.        }
  128.        /*  We have now established that the number can be  */
  129.        /*  represented without overflow or underflow  */
  130.        if (expt < 0)
  131.             {
  132.             expt = -expt;
  133.             fp_scale = 0.1;
  134.             }
  135.         else
  136.             fp_scale = 10.0;
  137.         while (expt)
  138.             {
  139.             if (expt&1) fp_tot *= fp_scale;
  140.             expt >>= 1;
  141.             fp_scale *= fp_scale;
  142.             }
  143.        errno = 0;
  144.        return fp_tot*sign;
  145.     }
  146.  
  147.