⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 strtod.c

📁 gcc的组建
💻 C
字号:
/*FUNCTION        <<strtod>>, <<strtodf>>---string to double or floatINDEX	strtodINDEX	_strtod_rINDEX	strtodfANSI_SYNOPSIS        #include <stdlib.h>        double strtod(const char *<[str]>, char **<[tail]>);        float strtodf(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 strtodf(<[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]>.	<<strtodf>> 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 <string.h>#include <float.h>#include <errno.h>#include "mprec.h"double_DEFUN (_strtod_r, (ptr, s00, se),	struct _Jv_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;  int digits = 0;  /* Number of digits found in fraction part. */  long e;  _CONST char *s, *s0, *s1;  double aadj, aadj1, adj;  long L;  unsigned long y, z;  union double_union rv, rv0;  _Jv_Bigint *bb = NULL, *bb1, *bd = NULL, *bd0, *bs = NULL, *delta = NULL;  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')    {      digits++;      nz0 = 1;      while (*++s == '0')	digits++;      if (!*s)	goto ret;    }  s0 = s;  y = z = 0;  for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)    {      digits++;      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)	    {	      digits++;	      nz++;	    }	  if (c > '0' && c <= '9')	    {	      digits++;	      s0 = s;	      nf += nz;	      nz = 0;	      goto have_dig;	    }	  goto dig_done;	}      for (; c >= '0' && c <= '9'; c = *++s)	{	  digits++;	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	{	  /* No exponent after an 'E' : that's an error. */	  ptr->_errno = EINVAL;	  e = 0;	  s = s00;	  goto ret;	}    }  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))	rv.d *= tens[i];      if (e1 &= ~15)	{	  if (e1 > DBL_MAX_10_EXP)	    {	    ovfl:	      ptr->_errno = ERANGE;	      /* Force result to IEEE infinity. */	      word0 (rv) = Exp_mask;	      word1 (rv) = 0;	      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		}	      else		word0 (rv) += P * Exp_msk1;	    }	}    }  else if (e1 < 0)    {      e1 = -e1;      if ((i = e1 & 15))	rv.d /= tens[i];      if (e1 &= ~15)	{	  e1 >>= 4;	  if (e1 >= 1 << n_bigtens)            goto undfl;	  for (j = 0; e1 > 1; j++, e1 >>= 1)	    if (e1 & 1)	      rv.d *= tinytens[j];	  /* The last multiplication could underflow. */	  rv0.d = rv.d;	  rv.d *= tinytens[j];	  if (!rv.d)	    {	      rv.d = 2. * rv0.d;	      rv.d *= tinytens[j];	      if (!rv.d)		{		undfl:		  rv.d = 0.;		  ptr->_errno = ERANGE;		  if (bd0)		    goto retfree;		  goto ret;		}#ifndef _DOUBLE_IS_32BITS	      word0 (rv) = Tiny0;	      word1 (rv) = Tiny1;#else	      word0 (rv) = Tiny1;#endif	      /* The refinement below will clean	       * this approximation up.	       */	    }	}    }  /* Now the hard part -- adjusting rv to the correct value.*/  /* Put digits into bd: true value = bd * 10^e */  bd0 = s2b (ptr, s0, nd0, nd, y);  for (;;)    {      bd = Balloc (ptr, bd0->_k);      Bcopy (bd, bd0);      bb = d2b (ptr, rv.d, &bbe, &bbbits);	/* rv.d = bb * 2^bbe */      bs = i2b (ptr, 1);      if (e >= 0)	{	  bb2 = bb5 = 0;	  bd2 = bd5 = e;	}      else	{	  bb2 = bb5 = -e;	  bd2 = bd5 = 0;	}      if (bbe >= 0)	bb2 += bbe;      else	bd2 -= bbe;      bs2 = bb2;#ifdef Sudden_Underflow#ifdef IBM      j = 1 + 4 * P - 3 - bbbits + ((bbe + bbbits - 1) & 3);#else      j = P + 1 - bbbits;#endif#else      i = bbe + bbbits - 1;	/* logb(rv.d) */      if (i < Emin)		/* denormal */	j = bbe + (P - Emin);      else	j = P + 1 - bbbits;#endif      bb2 += j;      bd2 += j;      i = bb2 < bd2 ? bb2 : bd2;      if (i > bs2)	i = bs2;      if (i > 0)	{	  bb2 -= i;	  bd2 -= i;	  bs2 -= i;	}      if (bb5 > 0)	{	  bs = pow5mult (ptr, bs, bb5);	  bb1 = mult (ptr, bs, bb);	  Bfree (ptr, bb);	  bb = bb1;	}      if (bb2 > 0)	bb = lshift (ptr, bb, bb2);      if (bd5 > 0)	bd = pow5mult (ptr, bd, bd5);      if (bd2 > 0)	bd = lshift (ptr, bd, bd2);      if (bs2 > 0)	bs = lshift (ptr, bs, bs2);      delta = diff (ptr, bb, bd);      dsign = delta->_sign;      delta->_sign = 0;      i = cmp (delta, bs);      if (i < 0)	{	  /* Error is less than half an ulp -- check for	   * special case of mantissa a power of two.	   */	  if (dsign || word1 (rv) || word0 (rv) & Bndry_mask)	    break;	  delta = lshift (ptr, delta, Log2P);	  if (cmp (delta, bs) > 0)	    goto drop_down;	  break;	}      if (i == 0)	{	  /* exactly half-way between */	  if (dsign)	    {	      if ((word0 (rv) & Bndry_mask1) == Bndry_mask1		  && word1 (rv) == 0xffffffff)		{		  /*boundary case -- increment exponent*/		  word0 (rv) = (word0 (rv) & Exp_mask)		    + Exp_msk1#ifdef IBM		    | Exp_msk1 >> 4#endif		    ;#ifndef _DOUBLE_IS_32BITS		  word1 (rv) = 0;#endif		  break;		}	    }	  else if (!(word0 (rv) & Bndry_mask) && !word1 (rv))	    {	    drop_down:	      /* boundary case -- decrement exponent */#ifdef Sudden_Underflow	      L = word0 (rv) & Exp_mask;#ifdef IBM	      if (L < Exp_msk1)#else	      if (L <= Exp_msk1)#endif		goto undfl;	      L -= Exp_msk1;#else	      L = (word0 (rv) & Exp_mask) - Exp_msk1;#endif	      word0 (rv) = L | Bndry_mask1;#ifndef _DOUBLE_IS_32BITS	      word1 (rv) = 0xffffffff;#endif#ifdef IBM	      goto cont;#else	      break;#endif	    }#ifndef ROUND_BIASED	  if (!(word1 (rv) & LSB))	    break;#endif	  if (dsign)	    rv.d += ulp (rv.d);#ifndef ROUND_BIASED	  else	    {	      rv.d -= ulp (rv.d);#ifndef Sudden_Underflow	      if (!rv.d)		goto undfl;#endif	    }#endif	  break;	}      if ((aadj = ratio (delta, bs)) <= 2.)	{	  if (dsign)	    aadj = aadj1 = 1.;	  else if (word1 (rv) || word0 (rv) & Bndry_mask)	    {#ifndef Sudden_Underflow	      if (word1 (rv) == Tiny1 && !word0 (rv))		goto undfl;#endif	      aadj = 1.;	      aadj1 = -1.;	    }	  else	    {	      /* special case -- power of FLT_RADIX to be */	      /* rounded down... */	      if (aadj < 2. / FLT_RADIX)		aadj = 1. / FLT_RADIX;	      else		aadj *= 0.5;	      aadj1 = -aadj;	    }	}      else	{	  aadj *= 0.5;	  aadj1 = dsign ? aadj : -aadj;#ifdef Check_FLT_ROUNDS	  switch (FLT_ROUNDS)	    {	    case 2:		/* towards +infinity */	      aadj1 -= 0.5;	      break;	    case 0:		/* towards 0 */	    case 3:		/* towards -infinity */	      aadj1 += 0.5;	    }#else	  if (FLT_ROUNDS == 0)	    aadj1 += 0.5;#endif	}      y = word0 (rv) & Exp_mask;      /* Check for overflow */      if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1))	{	  rv0.d = rv.d;	  word0 (rv) -= P * Exp_msk1;	  adj = aadj1 * ulp (rv.d);	  rv.d += adj;	  if ((word0 (rv) & Exp_mask) >=	      Exp_msk1 * (DBL_MAX_EXP + Bias - P))	    {	      if (word0 (rv0) == Big0 && word1 (rv0) == Big1)		goto ovfl;#ifdef _DOUBLE_IS_32BITS	      word0 (rv) = Big1;#else	      word0 (rv) = Big0;	      word1 (rv) = Big1;#endif	      goto cont;	    }	  else	    word0 (rv) += P * Exp_msk1;	}      else	{#ifdef Sudden_Underflow	  if ((word0 (rv) & Exp_mask) <= P * Exp_msk1)	    {	      rv0.d = rv.d;	      word0 (rv) += P * Exp_msk1;	      adj = aadj1 * ulp (rv.d);	      rv.d += adj;#ifdef IBM	      if ((word0 (rv) & Exp_mask) < P * Exp_msk1)#else	      if ((word0 (rv) & Exp_mask) <= P * Exp_msk1)#endif		{		  if (word0 (rv0) == Tiny0		      && word1 (rv0) == Tiny1)		    goto undfl;		  word0 (rv) = Tiny0;		  word1 (rv) = Tiny1;		  goto cont;		}	      else		word0 (rv) -= P * Exp_msk1;	    }	  else	    {	      adj = aadj1 * ulp (rv.d);	      rv.d += adj;	    }#else	  /* Compute adj so that the IEEE rounding rules will	   * correctly round rv.d + adj in some half-way cases.	   * If rv.d * ulp(rv.d) is denormalized (i.e.,	   * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid	   * trouble from bits lost to denormalization;	   * example: 1.2e-307 .	   */	  if (y <= (P - 1) * Exp_msk1 && aadj >= 1.)	    {	      aadj1 = (double) (int) (aadj + 0.5);	      if (!dsign)		aadj1 = -aadj1;	    }	  adj = aadj1 * ulp (rv.d);	  rv.d += adj;#endif	}      z = word0 (rv) & Exp_mask;      if (y == z)	{	  /* Can we stop now? */	  L = aadj;	  aadj -= L;	  /* The tolerances below are conservative. */	  if (dsign || word1 (rv) || word0 (rv) & Bndry_mask)	    {	      if (aadj < .4999999 || aadj > .5000001)		break;	    }	  else if (aadj < .4999999 / FLT_RADIX)	    break;	}    cont:      Bfree (ptr, bb);      Bfree (ptr, bd);      Bfree (ptr, bs);      Bfree (ptr, delta);    }retfree:  Bfree (ptr, bb);  Bfree (ptr, bd);  Bfree (ptr, bs);  Bfree (ptr, bd0);  Bfree (ptr, delta);ret:  if (se)    *se = (char *) s;  if (digits == 0)    ptr->_errno = EINVAL;  return sign ? -rv.d : rv.d;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -