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 + -
显示快捷键?