fiss

Friedel's Initialization and Service Supervision
Log | Files | Refs | LICENSE

strtod.c (9133B)


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