| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 | /* * Copyright (C) 2000 Manuel Novoa III * * Notes: * * The primary objective of this implementation was minimal size while * providing robustness and resonable accuracy. * * This implementation depends on IEEE floating point behavior and expects * to be able to generate +/- infinity as a result. * * There are a number of compile-time options below. * *//*****************************************************************************//*                            OPTIONS                                        *//*****************************************************************************//* Set if we want to scale with a O(log2(exp)) multiplications. */#define _STRTOD_LOG_SCALING      1/* Set if we want strtod to set errno appropriately. *//* NOTE: Implies all options below and pulls in _zero_or_inf_check. */#define _STRTOD_ERRNO            0/* Set if we want support for the endptr arg. *//* Implied by _STRTOD_ERRNO. */#define _STRTOD_ENDPTR           1/* Set if we want to prevent overflow in accumulating the exponent. */#define _STRTOD_RESTRICT_EXP     1/* Set if we want to process mantissa digits more intelligently. *//* Implied by _STRTOD_ERRNO. */#define _STRTOD_RESTRICT_DIGITS  1/* Set if we want to skip scaling 0 for the exponent. *//* Implied by _STRTOD_ERRNO. */#define _STRTOD_ZERO_CHECK       0/*****************************************************************************//* Don't change anything that follows.                                       *//*****************************************************************************/#if _STRTOD_ERRNO#undef _STRTOD_ENDPTR#undef _STRTOD_RESTRICT_EXP#undef _STRTOD_RESTRICT_DIGITS#undef _STRTOD_ZERO_CHECK#define _STRTOD_ENDPTR           1#define _STRTOD_RESTRICT_EXP     1#define _STRTOD_RESTRICT_DIGITS  1#define _STRTOD_ZERO_CHECK       1#endif/*****************************************************************************/#include <stdlib.h>#include <float.h>#if _STRTOD_RESTRICT_DIGITS#define MAX_SIG_DIGITS 20#define EXP_DENORM_ADJUST MAX_SIG_DIGITS#define MAX_ALLOWED_EXP (MAX_SIG_DIGITS  + EXP_DENORM_ADJUST - DBL_MIN_10_EXP)#if DBL_DIG > MAX_SIG_DIGITS#error need to adjust MAX_SIG_DIGITS#endif#include <limits.h>#if MAX_ALLOWED_EXP > INT_MAX#error size assumption violated for MAX_ALLOWED_EXP#endif#else/* We want some excess if we're not restricting mantissa digits. */#define MAX_ALLOWED_EXP ((20 - DBL_MIN_10_EXP) * 2)#endif#include <ctype.h>/* Note: For i386 the macro resulted in smaller code than the function call. */#if 1#undef isdigit#define isdigit(x) ( (x >= '0') && (x <= '9') )#endif#if _STRTOD_ERRNO#include <errno.h>extern int _zero_or_inf_check(double x);#endifdouble strtod(const char *str, char **endptr){    double number;#if _STRTOD_LOG_SCALING    double p10;#endif    char *pos0;#if _STRTOD_ENDPTR    char *pos1;#endif    char *pos = (char *) str;    int exponent_power;    int exponent_temp;    int negative;#if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR    int num_digits;#endif    while (isspace(*pos)) {	/* skip leading whitespace */	++pos;    }    negative = 0;    switch(*pos) {		/* handle optional sign */    case '-': negative = 1;	/* fall through to increment position */    case '+': ++pos;    }    number = 0.;#if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR    num_digits = -1;#endif    exponent_power = 0;    pos0 = NULL; LOOP:    while (isdigit(*pos)) {	/* process string of digits */#if _STRTOD_RESTRICT_DIGITS	if (num_digits < 0) {	/* first time through? */	    ++num_digits;	/* we've now seen a digit */	}	if (num_digits || (*pos != '0')) { /* had/have nonzero */	    ++num_digits;	    if (num_digits <= MAX_SIG_DIGITS) { /* is digit significant */		number = number * 10. + (*pos - '0');	    }	}#else#if _STRTOD_ENDPTR	++num_digits;#endif	number = number * 10. + (*pos - '0');#endif	++pos;    }    if ((*pos == '.') && !pos0) { /* is this the first decimal point? */	pos0 = ++pos;		/* save position of decimal point */	goto LOOP;		/* and process rest of digits */    }#if _STRTOD_ENDPTR    if (num_digits<0) {		/* must have at least one digit */	pos = (char *) str;	goto DONE;    }#endif#if _STRTOD_RESTRICT_DIGITS    if (num_digits > MAX_SIG_DIGITS) { /* adjust exponent for skipped digits */	exponent_power += num_digits - MAX_SIG_DIGITS;    }#endif    if (pos0) {	exponent_power += pos0 - pos; /* adjust exponent for decimal point */    }    if (negative) {		/* correct for sign */	number = -number;	negative = 0;		/* reset for exponent processing below */    }    /* process an exponent string */    if (*pos == 'e' || *pos == 'E') {#if _STRTOD_ENDPTR	pos1 = pos;#endif	switch(*++pos) {	/* handle optional sign */	case '-': negative = 1;	/* fall through to increment pos */	case '+': ++pos;	}	pos0 = pos;	exponent_temp = 0;	while (isdigit(*pos)) {	/* process string of digits */#if _STRTOD_RESTRICT_EXP	    if (exponent_temp < MAX_ALLOWED_EXP) { /* overflow check */		exponent_temp = exponent_temp * 10 + (*pos - '0');	    }#else	    exponent_temp = exponent_temp * 10 + (*pos - '0');#endif	    ++pos;	}#if _STRTOD_ENDPTR	if (pos == pos0) {	/* were there no digits? */	    pos = pos1;		/* back up to e|E */	} /* else */#endif	if (negative) {	    exponent_power -= exponent_temp;	} else {	    exponent_power += exponent_temp;	}    }#if _STRTOD_ZERO_CHECK    if (number == 0.) {	goto DONE;    }#endif    /* scale the result */#if _STRTOD_LOG_SCALING    exponent_temp = exponent_power;    p10 = 10.;    if (exponent_temp < 0) {	exponent_temp = -exponent_temp;    }    while (exponent_temp) {	if (exponent_temp & 1) {	    if (exponent_power < 0) {		number /= p10;	    } else {		number *= p10;	    }	}	exponent_temp >>= 1;	p10 *= p10;    }#else    while (exponent_power) {	if (exponent_power < 0) {	    number /= 10.;	    exponent_power++;	} else {	    number *= 10.;	    exponent_power--;	}    }#endif#if _STRTOD_ERRNO    if (_zero_or_inf_check(number)) {	__set_errno(ERANGE);    }#endif DONE:#if _STRTOD_ENDPTR    if (endptr) {	*endptr = pos;    }#endif    return number;}/* This should probably be in its own .o file.  Oh well. */double atof(const char *str){    return(strtod((str),(char**)0));}
 |