strtod.c
来自「用于嵌入式Linux系统的标准C的库函数」· C语言 代码 · 共 732 行 · 第 1/2 页
C
732 行
/*FUNCTION <<strtod>>, <<strtof>>---string to double or floatINDEX strtodINDEX _strtod_rINDEX strtofANSI_SYNOPSIS #include <stdlib.h> double strtod(const char *<[str]>, char **<[tail]>); float strtof(const char *<[str]>, char **<[tail]>); double _strtod_r(void *<[reent]>, const char *<[str]>, char **<[tail]>);TRAD_SYNOPSIS #include <stdlib.h> double strtod(<[str]>,<[tail]>) char *<[str]>; char **<[tail]>; float strtof(<[str]>,<[tail]>) char *<[str]>; char **<[tail]>; double _strtod_r(<[reent]>,<[str]>,<[tail]>) char *<[reent]>; char *<[str]>; char **<[tail]>;DESCRIPTION The function <<strtod>> parses the character string <[str]>, producing a substring which can be converted to a double value. The substring converted is the longest initial subsequence of <[str]>, beginning with the first non-whitespace character, that has the format: .[+|-]<[digits]>[.][<[digits]>][(e|E)[+|-]<[digits]>] The substring contains no characters if <[str]> is empty, consists entirely of whitespace, or if the first non-whitespace character is something other than <<+>>, <<->>, <<.>>, or a digit. If the substring is empty, no conversion is done, and the value of <[str]> is stored in <<*<[tail]>>>. Otherwise, the substring is converted, and a pointer to the final string (which will contain at least the terminating null character of <[str]>) is stored in <<*<[tail]>>>. If you want no assignment to <<*<[tail]>>>, pass a null pointer as <[tail]>. <<strtof>> is identical to <<strtod>> except for its return type. This implementation returns the nearest machine number to the input decimal string. Ties are broken by using the IEEE round-even rule. The alternate function <<_strtod_r>> is a reentrant version. The extra argument <[reent]> is a pointer to a reentrancy structure.RETURNS <<strtod>> returns the converted substring value, if any. If no conversion could be performed, 0 is returned. If the correct value is out of the range of representable values, plus or minus <<HUGE_VAL>> is returned, and <<ERANGE>> is stored in errno. If the correct value would cause underflow, 0 is returned and <<ERANGE>> is stored in errno.Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,<<lseek>>, <<read>>, <<sbrk>>, <<write>>.*//**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991 by AT&T. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************//* Please send bug reports to David M. Gay AT&T Bell Laboratories, Room 2C-463 600 Mountain Avenue Murray Hill, NJ 07974-2070 U.S.A. dmg@research.att.com or research!dmg */#include <_ansi.h>#include <reent.h>#include <string.h>#include "mprec.h"double_DEFUN (_strtod_r, (ptr, s00, se), struct _reent *ptr _AND _CONST char *s00 _AND char **se){ int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; long e; _CONST char *s, *s0, *s1; double aadj, aadj1, adj; long L; unsigned long z; __ULong y; union double_union rv, rv0; _Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; sign = nz0 = nz = 0; rv.d = 0.; for (s = s00;; s++) switch (*s) { case '-': sign = 1; /* no break */ case '+': if (*++s) goto break2; /* no break */ case 0: s = s00; goto ret; case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': continue; default: goto break2; }break2: if (*s == '0') { nz0 = 1; while (*++s == '0'); if (!*s) goto ret; } s0 = s; y = z = 0; for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) if (nd < 9) y = 10 * y + c - '0'; else if (nd < 16) z = 10 * z + c - '0'; nd0 = nd; if (c == '.') { c = *++s; if (!nd) { for (; c == '0'; c = *++s) nz++; if (c > '0' && c <= '9') { s0 = s; nf += nz; nz = 0; goto have_dig; } goto dig_done; } for (; c >= '0' && c <= '9'; c = *++s) { have_dig: nz++; if (c -= '0') { nf += nz; for (i = 1; i < nz; i++) if (nd++ < 9) y *= 10; else if (nd <= DBL_DIG + 1) z *= 10; if (nd++ < 9) y = 10 * y + c; else if (nd <= DBL_DIG + 1) z = 10 * z + c; nz = 0; } } }dig_done: e = 0; if (c == 'e' || c == 'E') { if (!nd && !nz && !nz0) { s = s00; goto ret; } s00 = s; esign = 0; switch (c = *++s) { case '-': esign = 1; case '+': c = *++s; } if (c >= '0' && c <= '9') { while (c == '0') c = *++s; if (c > '0' && c <= '9') { e = c - '0'; s1 = s; while ((c = *++s) >= '0' && c <= '9') e = 10 * e + c - '0'; if (s - s1 > 8) /* Avoid confusion from exponents * so large that e might overflow. */ e = 9999999L; if (esign) e = -e; } else e = 0; } else s = s00; } if (!nd) { if (!nz && !nz0) s = s00; goto ret; } e1 = e -= nf; /* Now we have nd0 digits, starting at s0, followed by a * decimal point, followed by nd-nd0 digits. The number we're * after is the integer represented by those digits times * 10**e */ if (!nd0) nd0 = nd; k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; rv.d = y; if (k > 9) rv.d = tens[k - 9] * rv.d + z; bd0 = 0; if (nd <= DBL_DIG#ifndef RND_PRODQUOT && FLT_ROUNDS == 1#endif ) { if (!e) goto ret; if (e > 0) { if (e <= Ten_pmax) {#ifdef VAX goto vax_ovfl_check;#else /* rv.d = */ rounded_product (rv.d, tens[e]); goto ret;#endif } i = DBL_DIG - nd; if (e <= Ten_pmax + i) { /* A fancier test would sometimes let us do * this for larger i values. */ e -= i; rv.d *= tens[i];#ifdef VAX /* VAX exponent range is so narrow we must * worry about overflow here... */ vax_ovfl_check: word0 (rv) -= P * Exp_msk1; /* rv.d = */ rounded_product (rv.d, tens[e]); if ((word0 (rv) & Exp_mask) > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) goto ovfl; word0 (rv) += P * Exp_msk1;#else /* rv.d = */ rounded_product (rv.d, tens[e]);#endif goto ret; } }#ifndef Inaccurate_Divide else if (e >= -Ten_pmax) { /* rv.d = */ rounded_quotient (rv.d, tens[-e]); goto ret; }#endif } e1 += nd - k; /* Get starting approximation = rv.d * 10**e1 */ if (e1 > 0) { if ((i = e1 & 15) != 0) rv.d *= tens[i]; if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: ptr->_errno = ERANGE;#ifdef _HAVE_STDC rv.d = HUGE_VAL;#else /* Can't trust HUGE_VAL */#ifdef IEEE_Arith word0 (rv) = Exp_mask;#ifndef _DOUBLE_IS_32BITS word1 (rv) = 0;#endif#else word0 (rv) = Big0;#ifndef _DOUBLE_IS_32BITS word1 (rv) = Big1;#endif#endif#endif if (bd0) goto retfree; goto ret; } if (e1 >>= 4) { for (j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) rv.d *= bigtens[j]; /* The last multiplication could overflow. */ word0 (rv) -= P * Exp_msk1; rv.d *= bigtens[j]; if ((z = word0 (rv) & Exp_mask) > Exp_msk1 * (DBL_MAX_EXP + Bias - P)) goto ovfl; if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) { /* set to largest number */ /* (Can't trust DBL_MAX) */ word0 (rv) = Big0;#ifndef _DOUBLE_IS_32BITS word1 (rv) = Big1;#endif }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?