xref: /plan9/sys/src/cmd/unix/drawterm/libc/strtod.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
18ccd4a63SDavid du Colombier #include <u.h>
28ccd4a63SDavid du Colombier #include <libc.h>
30d601874SDavid du Colombier #include "fmtdef.h"
40d601874SDavid du Colombier 
50d601874SDavid du Colombier static ulong
umuldiv(ulong a,ulong b,ulong c)60d601874SDavid du Colombier umuldiv(ulong a, ulong b, ulong c)
70d601874SDavid du Colombier {
80d601874SDavid du Colombier 	double d;
90d601874SDavid du Colombier 
100d601874SDavid du Colombier 	d = ((double)a * (double)b) / (double)c;
110d601874SDavid du Colombier 	if(d >= 4294967295.)
120d601874SDavid du Colombier 		d = 4294967295.;
130d601874SDavid du Colombier 	return (ulong)d;
140d601874SDavid du Colombier }
158ccd4a63SDavid du Colombier 
168ccd4a63SDavid du Colombier /*
178ccd4a63SDavid du Colombier  * This routine will convert to arbitrary precision
188ccd4a63SDavid du Colombier  * floating point entirely in multi-precision fixed.
198ccd4a63SDavid du Colombier  * The answer is the closest floating point number to
208ccd4a63SDavid du Colombier  * the given decimal number. Exactly half way are
218ccd4a63SDavid du Colombier  * rounded ala ieee rules.
228ccd4a63SDavid du Colombier  * Method is to scale input decimal between .500 and .999...
238ccd4a63SDavid du Colombier  * with external power of 2, then binary search for the
248ccd4a63SDavid du Colombier  * closest mantissa to this decimal number.
258ccd4a63SDavid du Colombier  * Nmant is is the required precision. (53 for ieee dp)
268ccd4a63SDavid du Colombier  * Nbits is the max number of bits/word. (must be <= 28)
278ccd4a63SDavid du Colombier  * Prec is calculated - the number of words of fixed mantissa.
288ccd4a63SDavid du Colombier  */
298ccd4a63SDavid du Colombier enum
308ccd4a63SDavid du Colombier {
310d601874SDavid du Colombier 	Nbits	= 28,				/* bits safely represented in a ulong */
320d601874SDavid du Colombier 	Nmant	= 53,				/* bits of precision required */
330d601874SDavid du Colombier 	Prec	= (Nmant+Nbits+1)/Nbits,	/* words of Nbits each to represent mantissa */
340d601874SDavid du Colombier 	Sigbit	= 1<<(Prec*Nbits-Nmant),	/* first significant bit of Prec-th word */
358ccd4a63SDavid du Colombier 	Ndig	= 1500,
368ccd4a63SDavid du Colombier 	One	= (ulong)(1<<Nbits),
378ccd4a63SDavid du Colombier 	Half	= (ulong)(One>>1),
388ccd4a63SDavid du Colombier 	Maxe	= 310,
398ccd4a63SDavid du Colombier 
400d601874SDavid du Colombier 	Fsign	= 1<<0,		/* found - */
410d601874SDavid du Colombier 	Fesign	= 1<<1,		/* found e- */
420d601874SDavid du Colombier 	Fdpoint	= 1<<2,		/* found . */
430d601874SDavid du Colombier 
440d601874SDavid du Colombier 	S0	= 0,		/* _		_S0	+S1	#S2	.S3 */
450d601874SDavid du Colombier 	S1,			/* _+		#S2	.S3 */
460d601874SDavid du Colombier 	S2,			/* _+#		#S2	.S4	eS5 */
470d601874SDavid du Colombier 	S3,			/* _+.		#S4 */
480d601874SDavid du Colombier 	S4,			/* _+#.#	#S4	eS5 */
490d601874SDavid du Colombier 	S5,			/* _+#.#e	+S6	#S7 */
500d601874SDavid du Colombier 	S6,			/* _+#.#e+	#S7 */
510d601874SDavid du Colombier 	S7,			/* _+#.#e+#	#S7 */
528ccd4a63SDavid du Colombier };
538ccd4a63SDavid du Colombier 
548ccd4a63SDavid du Colombier static	int	xcmp(char*, char*);
558ccd4a63SDavid du Colombier static	int	fpcmp(char*, ulong*);
568ccd4a63SDavid du Colombier static	void	frnorm(ulong*);
578ccd4a63SDavid du Colombier static	void	divascii(char*, int*, int*, int*);
588ccd4a63SDavid du Colombier static	void	mulascii(char*, int*, int*, int*);
598ccd4a63SDavid du Colombier 
608ccd4a63SDavid du Colombier typedef	struct	Tab	Tab;
618ccd4a63SDavid du Colombier struct	Tab
628ccd4a63SDavid du Colombier {
638ccd4a63SDavid du Colombier 	int	bp;
648ccd4a63SDavid du Colombier 	int	siz;
658ccd4a63SDavid du Colombier 	char*	cmp;
668ccd4a63SDavid du Colombier };
678ccd4a63SDavid du Colombier 
689cd23d14SDavid du Colombier #ifndef ERANGE
699cd23d14SDavid du Colombier #define ERANGE 12345
709cd23d14SDavid du Colombier #endif
719cd23d14SDavid du Colombier 
728ccd4a63SDavid du Colombier double
fmtstrtod(const char * as,char ** aas)730d601874SDavid du Colombier fmtstrtod(const char *as, char **aas)
748ccd4a63SDavid du Colombier {
750d601874SDavid du Colombier 	int na, ex, dp, bp, c, i, flag, state;
760d601874SDavid du Colombier 	ulong low[Prec], hig[Prec], mid[Prec];
778ccd4a63SDavid du Colombier 	double d;
788ccd4a63SDavid du Colombier 	char *s, a[Ndig];
798ccd4a63SDavid du Colombier 
800d601874SDavid du Colombier 	flag = 0;	/* Fsign, Fesign, Fdpoint */
810d601874SDavid du Colombier 	na = 0;		/* number of digits of a[] */
820d601874SDavid du Colombier 	dp = 0;		/* na of decimal point */
830d601874SDavid du Colombier 	ex = 0;		/* exonent */
848ccd4a63SDavid du Colombier 
858ccd4a63SDavid du Colombier 	state = S0;
860d601874SDavid du Colombier 	for(s=(char*)as;; s++) {
878ccd4a63SDavid du Colombier 		c = *s;
888ccd4a63SDavid du Colombier 		if(c >= '0' && c <= '9') {
898ccd4a63SDavid du Colombier 			switch(state) {
908ccd4a63SDavid du Colombier 			case S0:
918ccd4a63SDavid du Colombier 			case S1:
928ccd4a63SDavid du Colombier 			case S2:
938ccd4a63SDavid du Colombier 				state = S2;
948ccd4a63SDavid du Colombier 				break;
958ccd4a63SDavid du Colombier 			case S3:
968ccd4a63SDavid du Colombier 			case S4:
978ccd4a63SDavid du Colombier 				state = S4;
988ccd4a63SDavid du Colombier 				break;
998ccd4a63SDavid du Colombier 
1008ccd4a63SDavid du Colombier 			case S5:
1018ccd4a63SDavid du Colombier 			case S6:
1028ccd4a63SDavid du Colombier 			case S7:
1038ccd4a63SDavid du Colombier 				state = S7;
1048ccd4a63SDavid du Colombier 				ex = ex*10 + (c-'0');
1058ccd4a63SDavid du Colombier 				continue;
1068ccd4a63SDavid du Colombier 			}
1078ccd4a63SDavid du Colombier 			if(na == 0 && c == '0') {
1088ccd4a63SDavid du Colombier 				dp--;
1098ccd4a63SDavid du Colombier 				continue;
1108ccd4a63SDavid du Colombier 			}
1118ccd4a63SDavid du Colombier 			if(na < Ndig-50)
1128ccd4a63SDavid du Colombier 				a[na++] = c;
1138ccd4a63SDavid du Colombier 			continue;
1148ccd4a63SDavid du Colombier 		}
1158ccd4a63SDavid du Colombier 		switch(c) {
1168ccd4a63SDavid du Colombier 		case '\t':
1178ccd4a63SDavid du Colombier 		case '\n':
1188ccd4a63SDavid du Colombier 		case '\v':
1198ccd4a63SDavid du Colombier 		case '\f':
1208ccd4a63SDavid du Colombier 		case '\r':
1218ccd4a63SDavid du Colombier 		case ' ':
1228ccd4a63SDavid du Colombier 			if(state == S0)
1238ccd4a63SDavid du Colombier 				continue;
1248ccd4a63SDavid du Colombier 			break;
1258ccd4a63SDavid du Colombier 		case '-':
1268ccd4a63SDavid du Colombier 			if(state == S0)
1278ccd4a63SDavid du Colombier 				flag |= Fsign;
1288ccd4a63SDavid du Colombier 			else
1298ccd4a63SDavid du Colombier 				flag |= Fesign;
1308ccd4a63SDavid du Colombier 		case '+':
1318ccd4a63SDavid du Colombier 			if(state == S0)
1328ccd4a63SDavid du Colombier 				state = S1;
1338ccd4a63SDavid du Colombier 			else
1348ccd4a63SDavid du Colombier 			if(state == S5)
1358ccd4a63SDavid du Colombier 				state = S6;
1368ccd4a63SDavid du Colombier 			else
1370d601874SDavid du Colombier 				break;	/* syntax */
1388ccd4a63SDavid du Colombier 			continue;
1398ccd4a63SDavid du Colombier 		case '.':
1408ccd4a63SDavid du Colombier 			flag |= Fdpoint;
1418ccd4a63SDavid du Colombier 			dp = na;
1428ccd4a63SDavid du Colombier 			if(state == S0 || state == S1) {
1438ccd4a63SDavid du Colombier 				state = S3;
1448ccd4a63SDavid du Colombier 				continue;
1458ccd4a63SDavid du Colombier 			}
1468ccd4a63SDavid du Colombier 			if(state == S2) {
1478ccd4a63SDavid du Colombier 				state = S4;
1488ccd4a63SDavid du Colombier 				continue;
1498ccd4a63SDavid du Colombier 			}
1508ccd4a63SDavid du Colombier 			break;
1518ccd4a63SDavid du Colombier 		case 'e':
1528ccd4a63SDavid du Colombier 		case 'E':
1538ccd4a63SDavid du Colombier 			if(state == S2 || state == S4) {
1548ccd4a63SDavid du Colombier 				state = S5;
1558ccd4a63SDavid du Colombier 				continue;
1568ccd4a63SDavid du Colombier 			}
1578ccd4a63SDavid du Colombier 			break;
1588ccd4a63SDavid du Colombier 		}
1598ccd4a63SDavid du Colombier 		break;
1608ccd4a63SDavid du Colombier 	}
1618ccd4a63SDavid du Colombier 
1628ccd4a63SDavid du Colombier 	/*
1638ccd4a63SDavid du Colombier 	 * clean up return char-pointer
1648ccd4a63SDavid du Colombier 	 */
1658ccd4a63SDavid du Colombier 	switch(state) {
1668ccd4a63SDavid du Colombier 	case S0:
1678ccd4a63SDavid du Colombier 		if(xcmp(s, "nan") == 0) {
1688ccd4a63SDavid du Colombier 			if(aas != nil)
1698ccd4a63SDavid du Colombier 				*aas = s+3;
1708ccd4a63SDavid du Colombier 			goto retnan;
1718ccd4a63SDavid du Colombier 		}
1728ccd4a63SDavid du Colombier 	case S1:
1738ccd4a63SDavid du Colombier 		if(xcmp(s, "infinity") == 0) {
1748ccd4a63SDavid du Colombier 			if(aas != nil)
1758ccd4a63SDavid du Colombier 				*aas = s+8;
1768ccd4a63SDavid du Colombier 			goto retinf;
1778ccd4a63SDavid du Colombier 		}
1788ccd4a63SDavid du Colombier 		if(xcmp(s, "inf") == 0) {
1798ccd4a63SDavid du Colombier 			if(aas != nil)
1808ccd4a63SDavid du Colombier 				*aas = s+3;
1818ccd4a63SDavid du Colombier 			goto retinf;
1828ccd4a63SDavid du Colombier 		}
1838ccd4a63SDavid du Colombier 	case S3:
1848ccd4a63SDavid du Colombier 		if(aas != nil)
1850d601874SDavid du Colombier 			*aas = (char*)as;
1860d601874SDavid du Colombier 		goto ret0;	/* no digits found */
1878ccd4a63SDavid du Colombier 	case S6:
1880d601874SDavid du Colombier 		s--;		/* back over +- */
1898ccd4a63SDavid du Colombier 	case S5:
1900d601874SDavid du Colombier 		s--;		/* back over e */
1918ccd4a63SDavid du Colombier 		break;
1928ccd4a63SDavid du Colombier 	}
1938ccd4a63SDavid du Colombier 	if(aas != nil)
1948ccd4a63SDavid du Colombier 		*aas = s;
1958ccd4a63SDavid du Colombier 
1968ccd4a63SDavid du Colombier 	if(flag & Fdpoint)
1978ccd4a63SDavid du Colombier 	while(na > 0 && a[na-1] == '0')
1988ccd4a63SDavid du Colombier 		na--;
1998ccd4a63SDavid du Colombier 	if(na == 0)
2000d601874SDavid du Colombier 		goto ret0;	/* zero */
2018ccd4a63SDavid du Colombier 	a[na] = 0;
2028ccd4a63SDavid du Colombier 	if(!(flag & Fdpoint))
2038ccd4a63SDavid du Colombier 		dp = na;
2048ccd4a63SDavid du Colombier 	if(flag & Fesign)
2058ccd4a63SDavid du Colombier 		ex = -ex;
2068ccd4a63SDavid du Colombier 	dp += ex;
2070d601874SDavid du Colombier 	if(dp < -Maxe){
2080d601874SDavid du Colombier 		errno = ERANGE;
2090d601874SDavid du Colombier 		goto ret0;	/* underflow by exp */
2100d601874SDavid du Colombier 	} else
2118ccd4a63SDavid du Colombier 	if(dp > +Maxe)
2120d601874SDavid du Colombier 		goto retinf;	/* overflow by exp */
2138ccd4a63SDavid du Colombier 
2148ccd4a63SDavid du Colombier 	/*
2158ccd4a63SDavid du Colombier 	 * normalize the decimal ascii number
2168ccd4a63SDavid du Colombier 	 * to range .[5-9][0-9]* e0
2178ccd4a63SDavid du Colombier 	 */
2180d601874SDavid du Colombier 	bp = 0;		/* binary exponent */
2198ccd4a63SDavid du Colombier 	while(dp > 0)
2208ccd4a63SDavid du Colombier 		divascii(a, &na, &dp, &bp);
2218ccd4a63SDavid du Colombier 	while(dp < 0 || a[0] < '5')
2228ccd4a63SDavid du Colombier 		mulascii(a, &na, &dp, &bp);
2238ccd4a63SDavid du Colombier 
2248ccd4a63SDavid du Colombier 	/* close approx by naive conversion */
2250d601874SDavid du Colombier 	mid[0] = 0;
2260d601874SDavid du Colombier 	mid[1] = 1;
227*ec59a3ddSDavid du Colombier 	for(i=0; (c=a[i]); i++) {
2280d601874SDavid du Colombier 		mid[0] = mid[0]*10 + (c-'0');
2290d601874SDavid du Colombier 		mid[1] = mid[1]*10;
2300d601874SDavid du Colombier 		if(i >= 8)
2310d601874SDavid du Colombier 			break;
2328ccd4a63SDavid du Colombier 	}
2330d601874SDavid du Colombier 	low[0] = umuldiv(mid[0], One, mid[1]);
2340d601874SDavid du Colombier 	hig[0] = umuldiv(mid[0]+1, One, mid[1]);
2358ccd4a63SDavid du Colombier 	for(i=1; i<Prec; i++) {
2368ccd4a63SDavid du Colombier 		low[i] = 0;
2378ccd4a63SDavid du Colombier 		hig[i] = One-1;
2388ccd4a63SDavid du Colombier 	}
2398ccd4a63SDavid du Colombier 
2408ccd4a63SDavid du Colombier 	/* binary search for closest mantissa */
2418ccd4a63SDavid du Colombier 	for(;;) {
2428ccd4a63SDavid du Colombier 		/* mid = (hig + low) / 2 */
2438ccd4a63SDavid du Colombier 		c = 0;
2448ccd4a63SDavid du Colombier 		for(i=0; i<Prec; i++) {
2458ccd4a63SDavid du Colombier 			mid[i] = hig[i] + low[i];
2468ccd4a63SDavid du Colombier 			if(c)
2478ccd4a63SDavid du Colombier 				mid[i] += One;
2488ccd4a63SDavid du Colombier 			c = mid[i] & 1;
2498ccd4a63SDavid du Colombier 			mid[i] >>= 1;
2508ccd4a63SDavid du Colombier 		}
2518ccd4a63SDavid du Colombier 		frnorm(mid);
2528ccd4a63SDavid du Colombier 
2538ccd4a63SDavid du Colombier 		/* compare */
2548ccd4a63SDavid du Colombier 		c = fpcmp(a, mid);
2558ccd4a63SDavid du Colombier 		if(c > 0) {
2568ccd4a63SDavid du Colombier 			c = 1;
2578ccd4a63SDavid du Colombier 			for(i=0; i<Prec; i++)
2588ccd4a63SDavid du Colombier 				if(low[i] != mid[i]) {
2598ccd4a63SDavid du Colombier 					c = 0;
2608ccd4a63SDavid du Colombier 					low[i] = mid[i];
2618ccd4a63SDavid du Colombier 				}
2628ccd4a63SDavid du Colombier 			if(c)
2630d601874SDavid du Colombier 				break;	/* between mid and hig */
2648ccd4a63SDavid du Colombier 			continue;
2658ccd4a63SDavid du Colombier 		}
2668ccd4a63SDavid du Colombier 		if(c < 0) {
2678ccd4a63SDavid du Colombier 			for(i=0; i<Prec; i++)
2688ccd4a63SDavid du Colombier 				hig[i] = mid[i];
2698ccd4a63SDavid du Colombier 			continue;
2708ccd4a63SDavid du Colombier 		}
2718ccd4a63SDavid du Colombier 
2728ccd4a63SDavid du Colombier 		/* only hard part is if even/odd roundings wants to go up */
2738ccd4a63SDavid du Colombier 		c = mid[Prec-1] & (Sigbit-1);
2748ccd4a63SDavid du Colombier 		if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
2758ccd4a63SDavid du Colombier 			mid[Prec-1] -= c;
2760d601874SDavid du Colombier 		break;	/* exactly mid */
2778ccd4a63SDavid du Colombier 	}
2788ccd4a63SDavid du Colombier 
2798ccd4a63SDavid du Colombier 	/* normal rounding applies */
2808ccd4a63SDavid du Colombier 	c = mid[Prec-1] & (Sigbit-1);
2818ccd4a63SDavid du Colombier 	mid[Prec-1] -= c;
2828ccd4a63SDavid du Colombier 	if(c >= Sigbit/2) {
2838ccd4a63SDavid du Colombier 		mid[Prec-1] += Sigbit;
2848ccd4a63SDavid du Colombier 		frnorm(mid);
2858ccd4a63SDavid du Colombier 	}
2860d601874SDavid du Colombier 	goto out;
2878ccd4a63SDavid du Colombier 
2888ccd4a63SDavid du Colombier ret0:
2898ccd4a63SDavid du Colombier 	return 0;
2908ccd4a63SDavid du Colombier 
2918ccd4a63SDavid du Colombier retnan:
2928ccd4a63SDavid du Colombier 	return __NaN();
2938ccd4a63SDavid du Colombier 
2948ccd4a63SDavid du Colombier retinf:
2950d601874SDavid du Colombier 	/*
2960d601874SDavid du Colombier 	 * Unix strtod requires these.  Plan 9 would return Inf(0) or Inf(-1). */
2970d601874SDavid du Colombier 	errno = ERANGE;
2988ccd4a63SDavid du Colombier 	if(flag & Fsign)
2990d601874SDavid du Colombier 		return -HUGE_VAL;
3000d601874SDavid du Colombier 	return HUGE_VAL;
3010d601874SDavid du Colombier 
3020d601874SDavid du Colombier out:
3030d601874SDavid du Colombier 	d = 0;
3040d601874SDavid du Colombier 	for(i=0; i<Prec; i++)
3050d601874SDavid du Colombier 		d = d*One + mid[i];
3060d601874SDavid du Colombier 	if(flag & Fsign)
3070d601874SDavid du Colombier 		d = -d;
3080d601874SDavid du Colombier 	d = ldexp(d, bp - Prec*Nbits);
3090d601874SDavid du Colombier 	if(d == 0){	/* underflow */
3100d601874SDavid du Colombier 		errno = ERANGE;
3110d601874SDavid du Colombier 	}
3120d601874SDavid du Colombier 	return d;
3138ccd4a63SDavid du Colombier }
3148ccd4a63SDavid du Colombier 
3158ccd4a63SDavid du Colombier static void
frnorm(ulong * f)3168ccd4a63SDavid du Colombier frnorm(ulong *f)
3178ccd4a63SDavid du Colombier {
3188ccd4a63SDavid du Colombier 	int i, c;
3198ccd4a63SDavid du Colombier 
3208ccd4a63SDavid du Colombier 	c = 0;
3218ccd4a63SDavid du Colombier 	for(i=Prec-1; i>0; i--) {
3228ccd4a63SDavid du Colombier 		f[i] += c;
3238ccd4a63SDavid du Colombier 		c = f[i] >> Nbits;
3248ccd4a63SDavid du Colombier 		f[i] &= One-1;
3258ccd4a63SDavid du Colombier 	}
3268ccd4a63SDavid du Colombier 	f[0] += c;
3278ccd4a63SDavid du Colombier }
3288ccd4a63SDavid du Colombier 
3298ccd4a63SDavid du Colombier static int
fpcmp(char * a,ulong * f)3308ccd4a63SDavid du Colombier fpcmp(char *a, ulong* f)
3318ccd4a63SDavid du Colombier {
3328ccd4a63SDavid du Colombier 	ulong tf[Prec];
3338ccd4a63SDavid du Colombier 	int i, d, c;
3348ccd4a63SDavid du Colombier 
3358ccd4a63SDavid du Colombier 	for(i=0; i<Prec; i++)
3368ccd4a63SDavid du Colombier 		tf[i] = f[i];
3378ccd4a63SDavid du Colombier 
3388ccd4a63SDavid du Colombier 	for(;;) {
3398ccd4a63SDavid du Colombier 		/* tf *= 10 */
3408ccd4a63SDavid du Colombier 		for(i=0; i<Prec; i++)
3418ccd4a63SDavid du Colombier 			tf[i] = tf[i]*10;
3428ccd4a63SDavid du Colombier 		frnorm(tf);
3438ccd4a63SDavid du Colombier 		d = (tf[0] >> Nbits) + '0';
3448ccd4a63SDavid du Colombier 		tf[0] &= One-1;
3458ccd4a63SDavid du Colombier 
3468ccd4a63SDavid du Colombier 		/* compare next digit */
3478ccd4a63SDavid du Colombier 		c = *a;
3488ccd4a63SDavid du Colombier 		if(c == 0) {
3498ccd4a63SDavid du Colombier 			if('0' < d)
3508ccd4a63SDavid du Colombier 				return -1;
3518ccd4a63SDavid du Colombier 			if(tf[0] != 0)
3528ccd4a63SDavid du Colombier 				goto cont;
3538ccd4a63SDavid du Colombier 			for(i=1; i<Prec; i++)
3548ccd4a63SDavid du Colombier 				if(tf[i] != 0)
3558ccd4a63SDavid du Colombier 					goto cont;
3568ccd4a63SDavid du Colombier 			return 0;
3578ccd4a63SDavid du Colombier 		}
3588ccd4a63SDavid du Colombier 		if(c > d)
3598ccd4a63SDavid du Colombier 			return +1;
3608ccd4a63SDavid du Colombier 		if(c < d)
3618ccd4a63SDavid du Colombier 			return -1;
3628ccd4a63SDavid du Colombier 		a++;
3638ccd4a63SDavid du Colombier 	cont:;
3648ccd4a63SDavid du Colombier 	}
3658ccd4a63SDavid du Colombier }
3668ccd4a63SDavid du Colombier 
3678ccd4a63SDavid du Colombier static void
divby(char * a,int * na,int b)3680d601874SDavid du Colombier divby(char *a, int *na, int b)
3698ccd4a63SDavid du Colombier {
3708ccd4a63SDavid du Colombier 	int n, c;
3718ccd4a63SDavid du Colombier 	char *p;
3728ccd4a63SDavid du Colombier 
3738ccd4a63SDavid du Colombier 	p = a;
3748ccd4a63SDavid du Colombier 	n = 0;
3758ccd4a63SDavid du Colombier 	while(n>>b == 0) {
3768ccd4a63SDavid du Colombier 		c = *a++;
3778ccd4a63SDavid du Colombier 		if(c == 0) {
3788ccd4a63SDavid du Colombier 			while(n) {
3798ccd4a63SDavid du Colombier 				c = n*10;
3808ccd4a63SDavid du Colombier 				if(c>>b)
3818ccd4a63SDavid du Colombier 					break;
3828ccd4a63SDavid du Colombier 				n = c;
3838ccd4a63SDavid du Colombier 			}
3848ccd4a63SDavid du Colombier 			goto xx;
3858ccd4a63SDavid du Colombier 		}
3868ccd4a63SDavid du Colombier 		n = n*10 + c-'0';
3878ccd4a63SDavid du Colombier 		(*na)--;
3888ccd4a63SDavid du Colombier 	}
3898ccd4a63SDavid du Colombier 	for(;;) {
3908ccd4a63SDavid du Colombier 		c = n>>b;
3918ccd4a63SDavid du Colombier 		n -= c<<b;
3928ccd4a63SDavid du Colombier 		*p++ = c + '0';
3938ccd4a63SDavid du Colombier 		c = *a++;
3948ccd4a63SDavid du Colombier 		if(c == 0)
3958ccd4a63SDavid du Colombier 			break;
3968ccd4a63SDavid du Colombier 		n = n*10 + c-'0';
3978ccd4a63SDavid du Colombier 	}
3988ccd4a63SDavid du Colombier 	(*na)++;
3998ccd4a63SDavid du Colombier xx:
4008ccd4a63SDavid du Colombier 	while(n) {
4018ccd4a63SDavid du Colombier 		n = n*10;
4028ccd4a63SDavid du Colombier 		c = n>>b;
4038ccd4a63SDavid du Colombier 		n -= c<<b;
4048ccd4a63SDavid du Colombier 		*p++ = c + '0';
4058ccd4a63SDavid du Colombier 		(*na)++;
4068ccd4a63SDavid du Colombier 	}
4078ccd4a63SDavid du Colombier 	*p = 0;
4088ccd4a63SDavid du Colombier }
4098ccd4a63SDavid du Colombier 
4108ccd4a63SDavid du Colombier static	Tab	tab1[] =
4118ccd4a63SDavid du Colombier {
4128ccd4a63SDavid du Colombier 	 1,  0, "",
4138ccd4a63SDavid du Colombier 	 3,  1, "7",
4148ccd4a63SDavid du Colombier 	 6,  2, "63",
4158ccd4a63SDavid du Colombier 	 9,  3, "511",
4168ccd4a63SDavid du Colombier 	13,  4, "8191",
4178ccd4a63SDavid du Colombier 	16,  5, "65535",
4188ccd4a63SDavid du Colombier 	19,  6, "524287",
4198ccd4a63SDavid du Colombier 	23,  7, "8388607",
4208ccd4a63SDavid du Colombier 	26,  8, "67108863",
4218ccd4a63SDavid du Colombier 	27,  9, "134217727",
4228ccd4a63SDavid du Colombier };
4238ccd4a63SDavid du Colombier 
4248ccd4a63SDavid du Colombier static void
divascii(char * a,int * na,int * dp,int * bp)4258ccd4a63SDavid du Colombier divascii(char *a, int *na, int *dp, int *bp)
4268ccd4a63SDavid du Colombier {
4278ccd4a63SDavid du Colombier 	int b, d;
4288ccd4a63SDavid du Colombier 	Tab *t;
4298ccd4a63SDavid du Colombier 
4308ccd4a63SDavid du Colombier 	d = *dp;
4310d601874SDavid du Colombier 	if(d >= (int)(nelem(tab1)))
4320d601874SDavid du Colombier 		d = (int)(nelem(tab1))-1;
4338ccd4a63SDavid du Colombier 	t = tab1 + d;
4348ccd4a63SDavid du Colombier 	b = t->bp;
4358ccd4a63SDavid du Colombier 	if(memcmp(a, t->cmp, t->siz) > 0)
4368ccd4a63SDavid du Colombier 		d--;
4378ccd4a63SDavid du Colombier 	*dp -= d;
4388ccd4a63SDavid du Colombier 	*bp += b;
4398ccd4a63SDavid du Colombier 	divby(a, na, b);
4408ccd4a63SDavid du Colombier }
4418ccd4a63SDavid du Colombier 
4428ccd4a63SDavid du Colombier static void
mulby(char * a,char * p,char * q,int b)4438ccd4a63SDavid du Colombier mulby(char *a, char *p, char *q, int b)
4448ccd4a63SDavid du Colombier {
4458ccd4a63SDavid du Colombier 	int n, c;
4468ccd4a63SDavid du Colombier 
4478ccd4a63SDavid du Colombier 	n = 0;
4488ccd4a63SDavid du Colombier 	*p = 0;
4498ccd4a63SDavid du Colombier 	for(;;) {
4508ccd4a63SDavid du Colombier 		q--;
4518ccd4a63SDavid du Colombier 		if(q < a)
4528ccd4a63SDavid du Colombier 			break;
4538ccd4a63SDavid du Colombier 		c = *q - '0';
4548ccd4a63SDavid du Colombier 		c = (c<<b) + n;
4558ccd4a63SDavid du Colombier 		n = c/10;
4568ccd4a63SDavid du Colombier 		c -= n*10;
4578ccd4a63SDavid du Colombier 		p--;
4588ccd4a63SDavid du Colombier 		*p = c + '0';
4598ccd4a63SDavid du Colombier 	}
4608ccd4a63SDavid du Colombier 	while(n) {
4618ccd4a63SDavid du Colombier 		c = n;
4628ccd4a63SDavid du Colombier 		n = c/10;
4638ccd4a63SDavid du Colombier 		c -= n*10;
4648ccd4a63SDavid du Colombier 		p--;
4658ccd4a63SDavid du Colombier 		*p = c + '0';
4668ccd4a63SDavid du Colombier 	}
4678ccd4a63SDavid du Colombier }
4688ccd4a63SDavid du Colombier 
4698ccd4a63SDavid du Colombier static	Tab	tab2[] =
4708ccd4a63SDavid du Colombier {
4710d601874SDavid du Colombier 	 1,  1, "",				/* dp = 0-0 */
4728ccd4a63SDavid du Colombier 	 3,  3, "125",
4738ccd4a63SDavid du Colombier 	 6,  5, "15625",
4748ccd4a63SDavid du Colombier 	 9,  7, "1953125",
4758ccd4a63SDavid du Colombier 	13, 10, "1220703125",
4768ccd4a63SDavid du Colombier 	16, 12, "152587890625",
4778ccd4a63SDavid du Colombier 	19, 14, "19073486328125",
4788ccd4a63SDavid du Colombier 	23, 17, "11920928955078125",
4798ccd4a63SDavid du Colombier 	26, 19, "1490116119384765625",
4800d601874SDavid du Colombier 	27, 19, "7450580596923828125",		/* dp 8-9 */
4818ccd4a63SDavid du Colombier };
4828ccd4a63SDavid du Colombier 
4838ccd4a63SDavid du Colombier static void
mulascii(char * a,int * na,int * dp,int * bp)4848ccd4a63SDavid du Colombier mulascii(char *a, int *na, int *dp, int *bp)
4858ccd4a63SDavid du Colombier {
4868ccd4a63SDavid du Colombier 	char *p;
4878ccd4a63SDavid du Colombier 	int d, b;
4888ccd4a63SDavid du Colombier 	Tab *t;
4898ccd4a63SDavid du Colombier 
4908ccd4a63SDavid du Colombier 	d = -*dp;
4910d601874SDavid du Colombier 	if(d >= (int)(nelem(tab2)))
4920d601874SDavid du Colombier 		d = (int)(nelem(tab2))-1;
4938ccd4a63SDavid du Colombier 	t = tab2 + d;
4948ccd4a63SDavid du Colombier 	b = t->bp;
4958ccd4a63SDavid du Colombier 	if(memcmp(a, t->cmp, t->siz) < 0)
4968ccd4a63SDavid du Colombier 		d--;
4978ccd4a63SDavid du Colombier 	p = a + *na;
4988ccd4a63SDavid du Colombier 	*bp -= b;
4998ccd4a63SDavid du Colombier 	*dp += d;
5008ccd4a63SDavid du Colombier 	*na += d;
5018ccd4a63SDavid du Colombier 	mulby(a, p+d, p, b);
5028ccd4a63SDavid du Colombier }
5038ccd4a63SDavid du Colombier 
5048ccd4a63SDavid du Colombier static int
xcmp(char * a,char * b)5058ccd4a63SDavid du Colombier xcmp(char *a, char *b)
5068ccd4a63SDavid du Colombier {
5078ccd4a63SDavid du Colombier 	int c1, c2;
5088ccd4a63SDavid du Colombier 
5098ccd4a63SDavid du Colombier 	while((c1 = *b++)) {
5108ccd4a63SDavid du Colombier 		c2 = *a++;
5118ccd4a63SDavid du Colombier 		if(isupper(c2))
5128ccd4a63SDavid du Colombier 			c2 = tolower(c2);
5138ccd4a63SDavid du Colombier 		if(c1 != c2)
5148ccd4a63SDavid du Colombier 			return 1;
5158ccd4a63SDavid du Colombier 	}
5168ccd4a63SDavid du Colombier 	return 0;
5178ccd4a63SDavid du Colombier }
518