github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/src/lib9/fmt/strtod.c (about)

     1  /*
     2   * The authors of this software are Rob Pike and Ken Thompson,
     3   * with contributions from Mike Burrows and Sean Dorward.
     4   *
     5   *     Copyright (c) 2002-2006 by Lucent Technologies.
     6   *     Portions Copyright (c) 2004 Google Inc.
     7   * 
     8   * Permission to use, copy, modify, and distribute this software for any
     9   * purpose without fee is hereby granted, provided that this entire notice
    10   * is included in all copies of any software which is or includes a copy
    11   * or modification of this software and in all copies of the supporting
    12   * documentation for such software.
    13   * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
    14   * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES 
    15   * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
    16   * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
    17   */
    18  
    19  #include <u.h>
    20  #include <errno.h>
    21  #include <libc.h>
    22  #include "fmtdef.h"
    23  
    24  static ulong
    25  umuldiv(ulong a, ulong b, ulong c)
    26  {
    27  	double d;
    28  
    29  	d = ((double)a * (double)b) / (double)c;
    30  	if(d >= 4294967295.)
    31  		d = 4294967295.;
    32  	return (ulong)d;
    33  }
    34  
    35  /*
    36   * This routine will convert to arbitrary precision
    37   * floating point entirely in multi-precision fixed.
    38   * The answer is the closest floating point number to
    39   * the given decimal number. Exactly half way are
    40   * rounded ala ieee rules.
    41   * Method is to scale input decimal between .500 and .999...
    42   * with external power of 2, then binary search for the
    43   * closest mantissa to this decimal number.
    44   * Nmant is is the required precision. (53 for ieee dp)
    45   * Nbits is the max number of bits/word. (must be <= 28)
    46   * Prec is calculated - the number of words of fixed mantissa.
    47   */
    48  enum
    49  {
    50  	Nbits	= 28,				/* bits safely represented in a ulong */
    51  	Nmant	= 53,				/* bits of precision required */
    52  	Prec	= (Nmant+Nbits+1)/Nbits,	/* words of Nbits each to represent mantissa */
    53  	Sigbit	= 1<<(Prec*Nbits-Nmant),	/* first significant bit of Prec-th word */
    54  	Ndig	= 1500,
    55  	One	= (ulong)(1<<Nbits),
    56  	Half	= (ulong)(One>>1),
    57  	Maxe	= 310,
    58  
    59  	Fsign	= 1<<0,		/* found - */
    60  	Fesign	= 1<<1,		/* found e- */
    61  	Fdpoint	= 1<<2,		/* found . */
    62  
    63  	S0	= 0,		/* _		_S0	+S1	#S2	.S3 */
    64  	S1,			/* _+		#S2	.S3 */
    65  	S2,			/* _+#		#S2	.S4	eS5 */
    66  	S3,			/* _+.		#S4 */
    67  	S4,			/* _+#.#	#S4	eS5 */
    68  	S5,			/* _+#.#e	+S6	#S7 */
    69  	S6,			/* _+#.#e+	#S7 */
    70  	S7			/* _+#.#e+#	#S7 */
    71  };
    72  
    73  static	int	xcmp(char*, char*);
    74  static	int	fpcmp(char*, ulong*);
    75  static	void	frnorm(ulong*);
    76  static	void	divascii(char*, int*, int*, int*);
    77  static	void	mulascii(char*, int*, int*, int*);
    78  
    79  typedef	struct	Tab	Tab;
    80  struct	Tab
    81  {
    82  	int	bp;
    83  	int	siz;
    84  	char*	cmp;
    85  };
    86  
    87  double
    88  fmtstrtod(const char *as, char **aas)
    89  {
    90  	int na, ex, dp, bp, c, i, flag, state;
    91  	ulong low[Prec], hig[Prec], mid[Prec];
    92  	double d;
    93  	char *s, a[Ndig];
    94  
    95  	flag = 0;	/* Fsign, Fesign, Fdpoint */
    96  	na = 0;		/* number of digits of a[] */
    97  	dp = 0;		/* na of decimal point */
    98  	ex = 0;		/* exonent */
    99  
   100  	state = S0;
   101  	for(s=(char*)as;; s++) {
   102  		c = *s;
   103  		if(c >= '0' && c <= '9') {
   104  			switch(state) {
   105  			case S0:
   106  			case S1:
   107  			case S2:
   108  				state = S2;
   109  				break;
   110  			case S3:
   111  			case S4:
   112  				state = S4;
   113  				break;
   114  
   115  			case S5:
   116  			case S6:
   117  			case S7:
   118  				state = S7;
   119  				ex = ex*10 + (c-'0');
   120  				continue;
   121  			}
   122  			if(na == 0 && c == '0') {
   123  				dp--;
   124  				continue;
   125  			}
   126  			if(na < Ndig-50)
   127  				a[na++] = (char)c;
   128  			continue;
   129  		}
   130  		switch(c) {
   131  		case '\t':
   132  		case '\n':
   133  		case '\v':
   134  		case '\f':
   135  		case '\r':
   136  		case ' ':
   137  			if(state == S0)
   138  				continue;
   139  			break;
   140  		case '-':
   141  			if(state == S0)
   142  				flag |= Fsign;
   143  			else
   144  				flag |= Fesign;
   145  		case '+':
   146  			if(state == S0)
   147  				state = S1;
   148  			else
   149  			if(state == S5)
   150  				state = S6;
   151  			else
   152  				break;	/* syntax */
   153  			continue;
   154  		case '.':
   155  			flag |= Fdpoint;
   156  			dp = na;
   157  			if(state == S0 || state == S1) {
   158  				state = S3;
   159  				continue;
   160  			}
   161  			if(state == S2) {
   162  				state = S4;
   163  				continue;
   164  			}
   165  			break;
   166  		case 'e':
   167  		case 'E':
   168  			if(state == S2 || state == S4) {
   169  				state = S5;
   170  				continue;
   171  			}
   172  			break;
   173  		}
   174  		break;
   175  	}
   176  
   177  	/*
   178  	 * clean up return char-pointer
   179  	 */
   180  	switch(state) {
   181  	case S0:
   182  		if(xcmp(s, "nan") == 0) {
   183  			if(aas != nil)
   184  				*aas = s+3;
   185  			goto retnan;
   186  		}
   187  	case S1:
   188  		if(xcmp(s, "infinity") == 0) {
   189  			if(aas != nil)
   190  				*aas = s+8;
   191  			goto retinf;
   192  		}
   193  		if(xcmp(s, "inf") == 0) {
   194  			if(aas != nil)
   195  				*aas = s+3;
   196  			goto retinf;
   197  		}
   198  	case S3:
   199  		if(aas != nil)
   200  			*aas = (char*)as;
   201  		goto ret0;	/* no digits found */
   202  	case S6:
   203  		s--;		/* back over +- */
   204  	case S5:
   205  		s--;		/* back over e */
   206  		break;
   207  	}
   208  	if(aas != nil)
   209  		*aas = s;
   210  
   211  	if(flag & Fdpoint)
   212  	while(na > 0 && a[na-1] == '0')
   213  		na--;
   214  	if(na == 0)
   215  		goto ret0;	/* zero */
   216  	a[na] = 0;
   217  	if(!(flag & Fdpoint))
   218  		dp = na;
   219  	if(flag & Fesign)
   220  		ex = -ex;
   221  	dp += ex;
   222  	if(dp < -Maxe){
   223  		errno = ERANGE;
   224  		goto ret0;	/* underflow by exp */
   225  	} else
   226  	if(dp > +Maxe)
   227  		goto retinf;	/* overflow by exp */
   228  
   229  	/*
   230  	 * normalize the decimal ascii number
   231  	 * to range .[5-9][0-9]* e0
   232  	 */
   233  	bp = 0;		/* binary exponent */
   234  	while(dp > 0)
   235  		divascii(a, &na, &dp, &bp);
   236  	while(dp < 0 || a[0] < '5')
   237  		mulascii(a, &na, &dp, &bp);
   238  
   239  	/* close approx by naive conversion */
   240  	mid[0] = 0;
   241  	mid[1] = 1;
   242  	for(i=0; (c=a[i]) != '\0'; i++) {
   243  		mid[0] = mid[0]*10 + (ulong)(c-'0');
   244  		mid[1] = mid[1]*10;
   245  		if(i >= 8)
   246  			break;
   247  	}
   248  	low[0] = umuldiv(mid[0], One, mid[1]);
   249  	hig[0] = umuldiv(mid[0]+1, One, mid[1]);
   250  	for(i=1; i<Prec; i++) {
   251  		low[i] = 0;
   252  		hig[i] = One-1;
   253  	}
   254  
   255  	/* binary search for closest mantissa */
   256  	for(;;) {
   257  		/* mid = (hig + low) / 2 */
   258  		c = 0;
   259  		for(i=0; i<Prec; i++) {
   260  			mid[i] = hig[i] + low[i];
   261  			if(c)
   262  				mid[i] += One;
   263  			c = mid[i] & 1;
   264  			mid[i] >>= 1;
   265  		}
   266  		frnorm(mid);
   267  
   268  		/* compare */
   269  		c = fpcmp(a, mid);
   270  		if(c > 0) {
   271  			c = 1;
   272  			for(i=0; i<Prec; i++)
   273  				if(low[i] != mid[i]) {
   274  					c = 0;
   275  					low[i] = mid[i];
   276  				}
   277  			if(c)
   278  				break;	/* between mid and hig */
   279  			continue;
   280  		}
   281  		if(c < 0) {
   282  			for(i=0; i<Prec; i++)
   283  				hig[i] = mid[i];
   284  			continue;
   285  		}
   286  
   287  		/* only hard part is if even/odd roundings wants to go up */
   288  		c = mid[Prec-1] & (Sigbit-1);
   289  		if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
   290  			mid[Prec-1] -= (ulong)c;
   291  		break;	/* exactly mid */
   292  	}
   293  
   294  	/* normal rounding applies */
   295  	c = mid[Prec-1] & (Sigbit-1);
   296  	mid[Prec-1] -= (ulong)c;
   297  	if(c >= Sigbit/2) {
   298  		mid[Prec-1] += Sigbit;
   299  		frnorm(mid);
   300  	}
   301  	goto out;
   302  
   303  ret0:
   304  	return 0;
   305  
   306  retnan:
   307  	return __NaN();
   308  
   309  retinf:
   310  	/*
   311  	 * Unix strtod requires these.  Plan 9 would return Inf(0) or Inf(-1). */
   312  	errno = ERANGE;
   313  	if(flag & Fsign)
   314  		return -HUGE_VAL;
   315  	return HUGE_VAL;
   316  
   317  out:
   318  	d = 0;
   319  	for(i=0; i<Prec; i++)
   320  		d = d*One + (double)mid[i];
   321  	if(flag & Fsign)
   322  		d = -d;
   323  	d = ldexp(d, bp - Prec*Nbits);
   324  	if(d == 0){	/* underflow */
   325  		errno = ERANGE;
   326  	}
   327  	return d;
   328  }
   329  
   330  static void
   331  frnorm(ulong *f)
   332  {
   333  	int i;
   334  	ulong c;
   335  
   336  	c = 0;
   337  	for(i=Prec-1; i>0; i--) {
   338  		f[i] += c;
   339  		c = f[i] >> Nbits;
   340  		f[i] &= One-1;
   341  	}
   342  	f[0] += c;
   343  }
   344  
   345  static int
   346  fpcmp(char *a, ulong* f)
   347  {
   348  	ulong tf[Prec];
   349  	int i, d, c;
   350  
   351  	for(i=0; i<Prec; i++)
   352  		tf[i] = f[i];
   353  
   354  	for(;;) {
   355  		/* tf *= 10 */
   356  		for(i=0; i<Prec; i++)
   357  			tf[i] = tf[i]*10;
   358  		frnorm(tf);
   359  		d = (int)(tf[0] >> Nbits) + '0';
   360  		tf[0] &= One-1;
   361  
   362  		/* compare next digit */
   363  		c = *a;
   364  		if(c == 0) {
   365  			if('0' < d)
   366  				return -1;
   367  			if(tf[0] != 0)
   368  				goto cont;
   369  			for(i=1; i<Prec; i++)
   370  				if(tf[i] != 0)
   371  					goto cont;
   372  			return 0;
   373  		}
   374  		if(c > d)
   375  			return +1;
   376  		if(c < d)
   377  			return -1;
   378  		a++;
   379  	cont:;
   380  	}
   381  }
   382  
   383  static void
   384  divby(char *a, int *na, int b)
   385  {
   386  	int n, c;
   387  	char *p;
   388  
   389  	p = a;
   390  	n = 0;
   391  	while(n>>b == 0) {
   392  		c = *a++;
   393  		if(c == 0) {
   394  			while(n) {
   395  				c = n*10;
   396  				if(c>>b)
   397  					break;
   398  				n = c;
   399  			}
   400  			goto xx;
   401  		}
   402  		n = n*10 + c-'0';
   403  		(*na)--;
   404  	}
   405  	for(;;) {
   406  		c = n>>b;
   407  		n -= c<<b;
   408  		*p++ = (char)(c + '0');
   409  		c = *a++;
   410  		if(c == 0)
   411  			break;
   412  		n = n*10 + c-'0';
   413  	}
   414  	(*na)++;
   415  xx:
   416  	while(n) {
   417  		n = n*10;
   418  		c = n>>b;
   419  		n -= c<<b;
   420  		*p++ = (char)(c + '0');
   421  		(*na)++;
   422  	}
   423  	*p = 0;
   424  }
   425  
   426  static	Tab	tab1[] =
   427  {
   428  	 1,  0, "",
   429  	 3,  1, "7",
   430  	 6,  2, "63",
   431  	 9,  3, "511",
   432  	13,  4, "8191",
   433  	16,  5, "65535",
   434  	19,  6, "524287",
   435  	23,  7, "8388607",
   436  	26,  8, "67108863",
   437  	27,  9, "134217727",
   438  };
   439  
   440  static void
   441  divascii(char *a, int *na, int *dp, int *bp)
   442  {
   443  	int b, d;
   444  	Tab *t;
   445  
   446  	d = *dp;
   447  	if(d >= (int)(nelem(tab1)))
   448  		d = (int)(nelem(tab1))-1;
   449  	t = tab1 + d;
   450  	b = t->bp;
   451  	if(memcmp(a, t->cmp, (size_t)t->siz) > 0)
   452  		d--;
   453  	*dp -= d;
   454  	*bp += b;
   455  	divby(a, na, b);
   456  }
   457  
   458  static void
   459  mulby(char *a, char *p, char *q, int b)
   460  {
   461  	int n, c;
   462  
   463  	n = 0;
   464  	*p = 0;
   465  	for(;;) {
   466  		q--;
   467  		if(q < a)
   468  			break;
   469  		c = *q - '0';
   470  		c = (c<<b) + n;
   471  		n = c/10;
   472  		c -= n*10;
   473  		p--;
   474  		*p = (char)(c + '0');
   475  	}
   476  	while(n) {
   477  		c = n;
   478  		n = c/10;
   479  		c -= n*10;
   480  		p--;
   481  		*p = (char)(c + '0');
   482  	}
   483  }
   484  
   485  static	Tab	tab2[] =
   486  {
   487  	 1,  1, "",				/* dp = 0-0 */
   488  	 3,  3, "125",
   489  	 6,  5, "15625",
   490  	 9,  7, "1953125",
   491  	13, 10, "1220703125",
   492  	16, 12, "152587890625",
   493  	19, 14, "19073486328125",
   494  	23, 17, "11920928955078125",
   495  	26, 19, "1490116119384765625",
   496  	27, 19, "7450580596923828125",		/* dp 8-9 */
   497  };
   498  
   499  static void
   500  mulascii(char *a, int *na, int *dp, int *bp)
   501  {
   502  	char *p;
   503  	int d, b;
   504  	Tab *t;
   505  
   506  	d = -*dp;
   507  	if(d >= (int)(nelem(tab2)))
   508  		d = (int)(nelem(tab2))-1;
   509  	t = tab2 + d;
   510  	b = t->bp;
   511  	if(memcmp(a, t->cmp, (size_t)t->siz) < 0)
   512  		d--;
   513  	p = a + *na;
   514  	*bp -= b;
   515  	*dp += d;
   516  	*na += d;
   517  	mulby(a, p+d, p, b);
   518  }
   519  
   520  static int
   521  xcmp(char *a, char *b)
   522  {
   523  	int c1, c2;
   524  
   525  	while((c1 = *b++) != '\0') {
   526  		c2 = *a++;
   527  		if(isupper(c2))
   528  			c2 = tolower(c2);
   529  		if(c1 != c2)
   530  			return 1;
   531  	}
   532  	return 0;
   533  }