📄 strtod.c
字号:
/* * 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));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -