home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tcl7.4 / compat / strtod.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-07  |  5.8 KB  |  260 lines

  1. /* 
  2.  * strtod.c --
  3.  *
  4.  *    Source code for the "strtod" library procedure.
  5.  *
  6.  * Copyright (c) 1988-1993 The Regents of the University of California.
  7.  * Copyright (c) 1994 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  */
  12.  
  13. #ifndef lint
  14. static char sccsid[] = "@(#) strtod.c 1.7 94/12/17 16:26:24";
  15. #endif /* not lint */
  16.  
  17. #include "tcl.h"
  18. #ifdef NO_STDLIB_H
  19. #   include "compat/stdlib.h"
  20. #else
  21. #   include <stdlib.h>
  22. #endif
  23. #include <ctype.h>
  24.  
  25. #ifndef TRUE
  26. #define TRUE 1
  27. #define FALSE 0
  28. #endif
  29. #ifndef NULL
  30. #define NULL 0
  31. #endif
  32.  
  33. static int maxExponent = 511;    /* Largest possible base 10 exponent.  Any
  34.                  * exponent larger than this will already
  35.                  * produce underflow or overflow, so there's
  36.                  * no need to worry about additional digits.
  37.                  */
  38. static double powersOf10[] = {    /* Table giving binary powers of 10.  Entry */
  39.     10.,            /* is 10^2^i.  Used to convert decimal */
  40.     100.,            /* exponents into floating-point numbers. */
  41.     1.0e4,
  42.     1.0e8,
  43.     1.0e16,
  44.     1.0e32,
  45.     1.0e64,
  46.     1.0e128,
  47.     1.0e256
  48. };
  49.  
  50. /*
  51.  *----------------------------------------------------------------------
  52.  *
  53.  * strtod --
  54.  *
  55.  *    This procedure converts a floating-point number from an ASCII
  56.  *    decimal representation to internal double-precision format.
  57.  *
  58.  * Results:
  59.  *    The return value is the double-precision floating-point
  60.  *    representation of the characters in string.  If endPtr isn't
  61.  *    NULL, then *endPtr is filled in with the address of the
  62.  *    next character after the last one that was part of the
  63.  *    floating-point number.
  64.  *
  65.  * Side effects:
  66.  *    None.
  67.  *
  68.  *----------------------------------------------------------------------
  69.  */
  70.  
  71. double
  72. strtod(string, endPtr)
  73.     CONST char *string;        /* A decimal ASCII floating-point number,
  74.                  * optionally preceded by white space.
  75.                  * Must have form "-I.FE-X", where I is the
  76.                  * integer part of the mantissa, F is the
  77.                  * fractional part of the mantissa, and X
  78.                  * is the exponent.  Either of the signs
  79.                  * may be "+", "-", or omitted.  Either I
  80.                  * or F may be omitted, or both.  The decimal
  81.                  * point isn't necessary unless F is present.
  82.                  * The "E" may actually be an "e".  E and X
  83.                  * may both be omitted (but not just one).
  84.                  */
  85.     char **endPtr;        /* If non-NULL, store terminating character's
  86.                  * address here. */
  87. {
  88.     int sign, expSign = FALSE;
  89.     double fraction, dblExp, *d;
  90.     register CONST char *p;
  91.     register int c;
  92.     int exp = 0;        /* Exponent read from "EX" field. */
  93.     int fracExp = 0;        /* Exponent that derives from the fractional
  94.                  * part.  Under normal circumstatnces, it is
  95.                  * the negative of the number of digits in F.
  96.                  * However, if I is very long, the last digits
  97.                  * of I get dropped (otherwise a long I with a
  98.                  * large negative exponent could cause an
  99.                  * unnecessary overflow on I alone).  In this
  100.                  * case, fracExp is incremented one for each
  101.                  * dropped digit. */
  102.     int mantSize;        /* Number of digits in mantissa. */
  103.     int decPt;            /* Number of mantissa digits BEFORE decimal
  104.                  * point. */
  105.     CONST char *pExp;        /* Temporarily holds location of exponent
  106.                  * in string. */
  107.  
  108.     /*
  109.      * Strip off leading blanks and check for a sign.
  110.      */
  111.  
  112.     p = string;
  113.     while (isspace(*p)) {
  114.     p += 1;
  115.     }
  116.     if (*p == '-') {
  117.     sign = TRUE;
  118.     p += 1;
  119.     } else {
  120.     if (*p == '+') {
  121.         p += 1;
  122.     }
  123.     sign = FALSE;
  124.     }
  125.  
  126.     /*
  127.      * Count the number of digits in the mantissa (including the decimal
  128.      * point), and also locate the decimal point.
  129.      */
  130.  
  131.     decPt = -1;
  132.     for (mantSize = 0; ; mantSize += 1)
  133.     {
  134.     c = *p;
  135.     if (!isdigit(c)) {
  136.         if ((c != '.') || (decPt >= 0)) {
  137.         break;
  138.         }
  139.         decPt = mantSize;
  140.     }
  141.     p += 1;
  142.     }
  143.  
  144.     /*
  145.      * Now suck up the digits in the mantissa.  Use two integers to
  146.      * collect 9 digits each (this is faster than using floating-point).
  147.      * If the mantissa has more than 18 digits, ignore the extras, since
  148.      * they can't affect the value anyway.
  149.      */
  150.     
  151.     pExp  = p;
  152.     p -= mantSize;
  153.     if (decPt < 0) {
  154.     decPt = mantSize;
  155.     } else {
  156.     mantSize -= 1;            /* One of the digits was the point. */
  157.     }
  158.     if (mantSize > 18) {
  159.     fracExp = decPt - 18;
  160.     mantSize = 18;
  161.     } else {
  162.     fracExp = decPt - mantSize;
  163.     }
  164.     if (mantSize == 0) {
  165.     fraction = 0.0;
  166.     p = string;
  167.     goto done;
  168.     } else {
  169.     int frac1, frac2;
  170.     frac1 = 0;
  171.     for ( ; mantSize > 9; mantSize -= 1)
  172.     {
  173.         c = *p;
  174.         p += 1;
  175.         if (c == '.') {
  176.         c = *p;
  177.         p += 1;
  178.         }
  179.         frac1 = 10*frac1 + (c - '0');
  180.     }
  181.     frac2 = 0;
  182.     for (; mantSize > 0; mantSize -= 1)
  183.     {
  184.         c = *p;
  185.         p += 1;
  186.         if (c == '.') {
  187.         c = *p;
  188.         p += 1;
  189.         }
  190.         frac2 = 10*frac2 + (c - '0');
  191.     }
  192.     fraction = (1.0e9 * frac1) + frac2;
  193.     }
  194.  
  195.     /*
  196.      * Skim off the exponent.
  197.      */
  198.  
  199.     p = pExp;
  200.     if ((*p == 'E') || (*p == 'e')) {
  201.     p += 1;
  202.     if (*p == '-') {
  203.         expSign = TRUE;
  204.         p += 1;
  205.     } else {
  206.         if (*p == '+') {
  207.         p += 1;
  208.         }
  209.         expSign = FALSE;
  210.     }
  211.     while (isdigit(*p)) {
  212.         exp = exp * 10 + (*p - '0');
  213.         p += 1;
  214.     }
  215.     }
  216.     if (expSign) {
  217.     exp = fracExp - exp;
  218.     } else {
  219.     exp = fracExp + exp;
  220.     }
  221.  
  222.     /*
  223.      * Generate a floating-point number that represents the exponent.
  224.      * Do this by processing the exponent one bit at a time to combine
  225.      * many powers of 2 of 10. Then combine the exponent with the
  226.      * fraction.
  227.      */
  228.     
  229.     if (exp < 0) {
  230.     expSign = TRUE;
  231.     exp = -exp;
  232.     } else {
  233.     expSign = FALSE;
  234.     }
  235.     if (exp > maxExponent) {
  236.     exp = maxExponent;
  237.     }
  238.     dblExp = 1.0;
  239.     for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
  240.     if (exp & 01) {
  241.         dblExp *= *d;
  242.     }
  243.     }
  244.     if (expSign) {
  245.     fraction /= dblExp;
  246.     } else {
  247.     fraction *= dblExp;
  248.     }
  249.  
  250. done:
  251.     if (endPtr != NULL) {
  252.     *endPtr = (char *) p;
  253.     }
  254.  
  255.     if (sign) {
  256.     return -fraction;
  257.     }
  258.     return fraction;
  259. }
  260.