Main Page | Alphabetical List | Class List | File List | Class Members | File Members

strtod.h

Go to the documentation of this file.
00001 #ifndef _STRTOD_H_
00002 #define _STRTOD_H_
00003 
00004 #include <nlibc.h>
00005 
00009 /*  Copyright (C) 2000, 2003     Manuel Novoa III
00010  *
00011  *  This library is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU Library General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2 of the License, or (at your option) any later version.
00015  *
00016  *  This library is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  Library General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU Library General Public
00022  *  License along with this library; if not, write to the Free
00023  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024  */
00025 
00026 
00027 /* Notes:
00028  *
00029  * The primary objective of this implementation was minimal size and
00030  * portablility, while providing robustness and resonable accuracy.
00031  *
00032  * This implementation depends on IEEE floating point behavior and expects
00033  * to be able to generate +/- infinity as a result.
00034  *
00035  * There are a number of compile-time options below.
00036  */
00037 
00038 /* July 27, 2003
00039  *
00040  * General cleanup and some minor size optimizations.
00041  * Change implementation to support __strtofpmax() rather than strtod().
00042  *   Now all the strto{floating pt}() funcs are implemented in terms of
00043  *   of the internal __strtofpmax() function.
00044  * Support "nan", "inf", and "infinity" strings (case-insensitive).
00045  * Support hexadecimal floating point notation.
00046  * Support wchar variants.
00047  * Support xlocale variants.
00048  *
00049  * TODO:
00050  *
00051  * Consider accumulating blocks of digits in longs to save floating pt mults.
00052  *   This would likely be much better on anything that only supported floats
00053  *   where DECIMAL_DIG == 9.  Actually, if floats have FLT_MAX_10_EXP == 38,
00054  *   we could calculate almost all the exponent multipliers (p_base) in
00055  *   long arithmetic as well.
00056  */
00057 
00058 /**********************************************************************/
00059 /**********************************************************************/
00060 
00061 /* Defined if we want to recognize "nan", "inf", and "infinity". (C99) */
00062 #define _STRTOD_NAN_INF_STRINGS  1
00063 
00064 /* Defined if we want support hexadecimal floating point notation. (C99) */
00065 /* Note!  Now controlled by uClibc configuration.  See below. */
00066 #define _STRTOD_HEXADECIMAL_FLOATS 1
00067 
00068 /* Defined if we want to scale with a O(log2(exp)) multiplications.
00069  * This is generally a good thing to do unless you are really tight
00070  * on space and do not expect to convert values of large magnitude. */
00071 
00072 #define _STRTOD_LOG_SCALING     1
00073 
00074 /* WARNING!!!   WARNING!!!   WARNING!!!   WARNING!!!   WARNING!!!
00075  *
00076  * Clearing any of the options below this point is not advised (or tested).
00077  *
00078  * WARNING!!!   WARNING!!!   WARNING!!!   WARNING!!!   WARNING!!! */
00079 
00080 /* Defined if we want strtod to set errno appropriately. */
00081 /* NOTE: Implies all options below. */
00082 #define _STRTOD_ERRNO           1
00083 
00084 /* Defined if we want support for the endptr arg. */
00085 /* Implied by _STRTOD_ERRNO. */
00086 #define _STRTOD_ENDPTR          1
00087 
00088 /* Defined if we want to prevent overflow in accumulating the exponent. */
00089 /* Implied by _STRTOD_ERRNO. */
00090 #define _STRTOD_RESTRICT_EXP    1
00091 
00092 /* Defined if we want to process mantissa digits more intelligently. */
00093 /* Implied by _STRTOD_ERRNO. */
00094 #define _STRTOD_RESTRICT_DIGITS 1
00095 
00096 /* Defined if we want to skip scaling 0 for the exponent. */
00097 /* Implied by _STRTOD_ERRNO. */
00098 #define _STRTOD_ZERO_CHECK      1
00099 
00100 /**********************************************************************/
00101 /* Don't change anything that follows.                                                                     */
00102 /**********************************************************************/
00103 
00104 #ifdef _STRTOD_ERRNO
00105 #undef _STRTOD_ENDPTR
00106 #undef _STRTOD_RESTRICT_EXP
00107 #undef _STRTOD_RESTRICT_DIGITS
00108 #undef _STRTOD_ZERO_CHECK
00109 #define _STRTOD_ENDPTR             1
00110 #define _STRTOD_RESTRICT_EXP     1
00111 #define _STRTOD_RESTRICT_DIGITS  1
00112 #define _STRTOD_ZERO_CHECK         1
00113 #endif
00114 
00115 /**********************************************************************/
00116 
00117 #define _ISOC99_SOURCE 1
00118 
00119 #define _STRTOD_HEXADECIMAL_FLOATS 1
00120 
00121 /**********************************************************************/
00122 
00123 #undef _STRTOD_FPMAX
00124 
00125 #define FPMAX_TYPE 2    // double is largest FP type
00126 typedef double  __fpmax_t;
00127 #define FPMAX_MIN_10_EXP DBL_MIN_10_EXP
00128 
00129 #define NEED_STRTOD_WRAPPER
00130 #define NEED_STRTOF_WRAPPER
00131 
00137 #define __FPMAX_ZERO_OR_INF_CHECK(x)  ((x) == ((x)/4) )
00138 
00139 /**********************************************************************/
00140 
00141 #ifdef _STRTOD_RESTRICT_DIGITS
00142 #define EXP_DENORM_ADJUST DECIMAL_DIG
00143 #define MAX_ALLOWED_EXP (DECIMAL_DIG  + EXP_DENORM_ADJUST - FPMAX_MIN_10_EXP)
00144 
00145 #if MAX_ALLOWED_EXP > INT_MAX
00146 #error size assumption violated for MAX_ALLOWED_EXP
00147 #endif
00148 #else
00149 /* We want some excess if we're not restricting mantissa digits. */
00150 #define MAX_ALLOWED_EXP ((20 - FPMAX_MIN_10_EXP) * 2)
00151 #endif
00152 
00153 
00154 #if defined(_STRTOD_RESTRICT_DIGITS) || defined(_STRTOD_ENDPTR) || defined(_STRTOD_HEXADECIMAL_FLOATS)
00155 #undef _STRTOD_NEED_NUM_DIGITS
00156 #define _STRTOD_NEED_NUM_DIGITS 1
00157 #endif
00158 
00159 /**********************************************************************/
00160 
00246 #ifndef __HAS_MAIN
00247 extern __fpmax_t strtod( const char *cstr, char **endptr );
00248 #else
00249 #if !defined(__cflow_processed) || defined(_uses_strtod_strtod_h)
00250 __fpmax_t strtod( const char *cstr, char **endptr )
00251 {
00252         __fpmax_t number;
00253         __fpmax_t p_base = 10;                  /* Adjusted to 16 in the hex case. */
00254         __fpmax_t exponent_power = 0;
00255         char *pos0;
00256 #ifdef _STRTOD_ENDPTR
00257         char *pos1;
00258 #endif
00259         char *pos;
00260         int exponent_temp;
00261         int negative; /* A flag for the number, a multiplier for the exponent. */
00262 #ifdef _STRTOD_NEED_NUM_DIGITS
00263         int num_digits;
00264 #endif
00265 
00266 #ifdef _STRTOD_HEXADECIMAL_FLOATS
00267         char expchar = 'e';
00268         char *poshex = NULL;
00269         typedef enum { ISdigit=0, ISXdigit=1 } cclass_t;
00270         cclass_t is_mask = ISdigit;
00271 #define EXPCHAR         expchar
00272 #define IS_X_DIGIT(c) ((is_mask==ISdigit) ? (isdigit((c))) : (isxdigit((c))))
00273 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
00274 #define EXPCHAR         'e'
00275 #define IS_X_DIGIT(C) isdigit((C))
00276 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
00277 
00278         /*
00279          * expand compacted string to char array for easy 
00280          * handling
00281          */
00282         char *str;
00283         int len = strlen( cstr );
00284         str = stringexpand( cstr, len );
00285 
00286         pos = (char *)str;
00287         while (isspace(*pos)) {         /* Skip leading whitespace. */
00288                 ++pos;
00289         }
00290 
00291         negative = 0;
00292         switch(*pos) {                          /* Handle optional sign. */
00293                 case '-': negative = 1; /* Fall through to increment position. */
00294                 case '+': ++pos;
00295         }
00296 
00297 #ifdef _STRTOD_HEXADECIMAL_FLOATS
00298         if ((*pos == '0') && (((pos[1])|0x20) == 'x')) {
00299                 poshex = ++pos;                 /* Save position of 'x' in case no digits */
00300                 ++pos;                                  /*   and advance past it.  */
00301                 is_mask = ISXdigit;     /* Used by IS_X_DIGIT. */
00302                 expchar = 'p';                  /* Adjust exponent char. */
00303                 p_base = 16;                    /* Adjust base multiplier. */
00304         }
00305 #endif
00306 
00307         number = 0.;
00308 #ifdef _STRTOD_NEED_NUM_DIGITS
00309         num_digits = -1;
00310 #endif
00311         pos0 = NULL;
00312 
00313  LOOP:
00314         while (IS_X_DIGIT(*pos)) {      /* Process string of (hex) digits. */
00315 #ifdef _STRTOD_RESTRICT_DIGITS
00316                 if (num_digits < 0) {   /* First time through? */
00317                         ++num_digits;           /* We've now seen a digit. */
00318                 }
00319                 if (num_digits || (*pos != '0')) { /* Had/have nonzero. */
00320                         ++num_digits;
00321                         if (num_digits <= DECIMAL_DIG) { /* Is digit significant? */
00322 #ifdef _STRTOD_HEXADECIMAL_FLOATS
00323                                 number = number * p_base
00324                                         + (isdigit(*pos)
00325                                            ? (*pos - '0')
00326                                            : (((*pos)|0x20) - ('a' - 10)));
00327 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
00328                                 number = number * p_base + (*pos - '0');
00329 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
00330                         }
00331                 }
00332 #else  /* _STRTOD_RESTRICT_DIGITS */
00333 #ifdef _STRTOD_NEED_NUM_DIGITS
00334                 ++num_digits;
00335 #endif
00336 #ifdef _STRTOD_HEXADECIMAL_FLOATS
00337                 number = number * p_base
00338                         + (isdigit(*pos)
00339                            ? (*pos - '0')
00340                            : (((*pos)|0x20) - ('a' - 10)));
00341 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
00342                 number = number * p_base + (*pos - '0');
00343 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
00344 #endif /* _STRTOD_RESTRICT_DIGITS */
00345                 ++pos;
00346         }
00347         if ((*pos == '.') && !pos0) { /* First decimal point? */
00348                 pos0 = ++pos;                   /* Save position of decimal point */
00349                 goto LOOP;                              /*   and process rest of digits. */
00350         }
00351 
00352 #ifdef _STRTOD_NEED_NUM_DIGITS
00353         if (num_digits<0) {                     /* Must have at least one digit. */
00354 #ifdef _STRTOD_HEXADECIMAL_FLOATS
00355                 if (poshex) {                   /* Back up to '0' in '0x' prefix. */
00356                         pos = poshex;
00357                         goto DONE;
00358                 }
00359 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
00360 
00361 #ifdef _STRTOD_NAN_INF_STRINGS
00362                 if (!pos0) {                    /* No decimal point, so check for inf/nan. */
00363                         /* Note: nan is the first string so 'number = i/0.;' works. */
00364                         static const char nan_inf_str[] = "\05nan\0\012infinity\0\05inf\0";
00365                         int i = 0;
00366 
00367                         do {
00368                                 /* Unfortunately, we have no memcasecmp(). */
00369                                 int j = 0;
00370                                 while (tolower(pos[j]) == nan_inf_str[i+1+j]) {
00371                                         ++j;
00372                                         if (!nan_inf_str[i+1+j]) {
00373                                                 number = i / 0.;
00374                                                 if (negative) { /* Correct for sign. */
00375                                                         number = -number;
00376                                                 }
00377                                                 pos += nan_inf_str[i] - 2;
00378                                                 goto DONE;
00379                                         }
00380                                 }
00381                                 i += nan_inf_str[i];
00382                         } while (nan_inf_str[i]);
00383                 }
00384 
00385 #endif /* STRTOD_NAN_INF_STRINGS */
00386 #ifdef _STRTOD_ENDPTR
00387                 pos = (char *) str;
00388 #endif
00389                 goto DONE;
00390         }
00391 #endif /* _STRTOD_NEED_NUM_DIGITS */
00392 
00393 #ifdef _STRTOD_RESTRICT_DIGITS
00394         if (num_digits > DECIMAL_DIG) { /* Adjust exponent for skipped digits. */
00395                 exponent_power += num_digits - DECIMAL_DIG;
00396         }
00397 #endif
00398 
00399         if (pos0) {
00400                 exponent_power += pos0 - pos; /* Adjust exponent for decimal point. */
00401         }
00402 
00403 #ifdef _STRTOD_HEXADECIMAL_FLOATS
00404         if (poshex) {
00405                 exponent_power *= 4;    /* Above is 2**4, but below is 2. */
00406                 p_base = 2;
00407         }
00408 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
00409 
00410         if (negative) {                         /* Correct for sign. */
00411                 number = -number;
00412         }
00413 
00414         /* process an exponent string */
00415         if (((*pos)|0x20) == EXPCHAR) {
00416 #ifdef _STRTOD_ENDPTR
00417                 pos1 = pos;
00418 #endif
00419                 negative = 1;
00420                 switch(*++pos) {                /* Handle optional sign. */
00421                         case '-': negative = -1; /* Fall through to increment pos. */
00422                         case '+': ++pos;
00423                 }
00424 
00425                 pos0 = pos;
00426                 exponent_temp = 0;
00427                 while (isdigit(*pos)) { /* Process string of digits. */
00428 #ifdef _STRTOD_RESTRICT_EXP
00429                         if (exponent_temp < MAX_ALLOWED_EXP) { /* Avoid overflow. */
00430                                 exponent_temp = exponent_temp * 10 + (*pos - '0');
00431                         }
00432 #else
00433                         exponent_temp = exponent_temp * 10 + (*pos - '0');
00434 #endif
00435                         ++pos;
00436                 }
00437 
00438 #ifdef _STRTOD_ENDPTR
00439                 if (pos == pos0) {      /* No digits? */
00440                         pos = pos1;             /* Back up to {e|E}/{p|P}. */
00441                 } /* else */
00442 #endif
00443 
00444                 exponent_power += negative * exponent_temp;
00445         }
00446 
00447 #ifdef _STRTOD_ZERO_CHECK
00448         if (number == 0.) {
00449                 goto DONE;
00450         }
00451 #endif
00452 
00453         /* scale the result */
00454 #ifdef _STRTOD_LOG_SCALING
00455         exponent_temp = exponent_power;
00456 
00457         if (exponent_temp < 0) {
00458                 exponent_temp = -exponent_temp;
00459         }
00460 
00461         while (exponent_temp) {
00462                 if (exponent_temp & 1) {
00463                         if (exponent_power < 0) {
00464                                 /* Warning... caluclating a factor for the exponent and
00465                                  * then dividing could easily be faster.  But doing so
00466                                  * might cause problems when dealing with denormals. */
00467                                 number /= p_base;
00468                         } else {
00469                                 number *= p_base;
00470                         }
00471                 }
00472                 exponent_temp >>= 1;
00473                 p_base *= p_base;
00474         }
00475 
00476 #else  /* _STRTOD_LOG_SCALING */
00477         while (exponent_power) {
00478                 if (exponent_power < 0) {
00479                         number /= p_base;
00480                         exponent_power++;
00481                 } else {
00482                         number *= p_base;
00483                         exponent_power--;
00484                 }
00485         }
00486 #endif /* _STRTOD_LOG_SCALING */
00487 
00488 #ifdef _STRTOD_ERRNO
00489         if (__FPMAX_ZERO_OR_INF_CHECK(number)) {
00490                 errno = ERANGE;
00491         }
00492 #endif /* _STRTOD_ERRNO */
00493 
00494  DONE:
00495 #ifdef _STRTOD_ENDPTR
00496         if (endptr) {
00497                 *endptr = cstr + (pos-str);
00498         }
00499 #endif  /* _STRTOD_ENDPTR */
00500 
00501         return number;
00502 }
00503 #endif // _uses_strtod_strtod_h
00504 #endif // Has Main
00505 
00506 /**********************************************************************/
00507 
00508 #define strtof(NPTR,ENDPTR) strtod((NPTR),(ENDPTR))
00509 #define strtold(NPTR,ENDPTR) strtod((NPTR),(ENDPTR))
00510 
00511 
00512 #endif // _STRTOD_H_

Generated on Fri Jul 14 10:51:32 2006 for nlibc by doxygen 1.3.5