xref: /plan9-contrib/sys/src/cmd/unix/drawterm/libc/strtod.c (revision 0d601874851962e88c6c60fdd2e637bba04e13c2)
1*0d601874SDavid du Colombier /*
2*0d601874SDavid du Colombier  * The authors of this software are Rob Pike and Ken Thompson.
3*0d601874SDavid du Colombier  *              Copyright (c) 2002 by Lucent Technologies.
4*0d601874SDavid du Colombier  * Permission to use, copy, modify, and distribute this software for any
5*0d601874SDavid du Colombier  * purpose without fee is hereby granted, provided that this entire notice
6*0d601874SDavid du Colombier  * is included in all copies of any software which is or includes a copy
7*0d601874SDavid du Colombier  * or modification of this software and in all copies of the supporting
8*0d601874SDavid du Colombier  * documentation for such software.
9*0d601874SDavid du Colombier  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
10*0d601874SDavid du Colombier  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
11*0d601874SDavid du Colombier  * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12*0d601874SDavid du Colombier  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13*0d601874SDavid du Colombier  */
148ccd4a63SDavid du Colombier #include <u.h>
158ccd4a63SDavid du Colombier #include <libc.h>
16*0d601874SDavid du Colombier #include "fmtdef.h"
17*0d601874SDavid du Colombier 
18*0d601874SDavid du Colombier static ulong
19*0d601874SDavid du Colombier umuldiv(ulong a, ulong b, ulong c)
20*0d601874SDavid du Colombier {
21*0d601874SDavid du Colombier 	double d;
22*0d601874SDavid du Colombier 
23*0d601874SDavid du Colombier 	d = ((double)a * (double)b) / (double)c;
24*0d601874SDavid du Colombier 	if(d >= 4294967295.)
25*0d601874SDavid du Colombier 		d = 4294967295.;
26*0d601874SDavid du Colombier 	return (ulong)d;
27*0d601874SDavid du Colombier }
288ccd4a63SDavid du Colombier 
298ccd4a63SDavid du Colombier /*
308ccd4a63SDavid du Colombier  * This routine will convert to arbitrary precision
318ccd4a63SDavid du Colombier  * floating point entirely in multi-precision fixed.
328ccd4a63SDavid du Colombier  * The answer is the closest floating point number to
338ccd4a63SDavid du Colombier  * the given decimal number. Exactly half way are
348ccd4a63SDavid du Colombier  * rounded ala ieee rules.
358ccd4a63SDavid du Colombier  * Method is to scale input decimal between .500 and .999...
368ccd4a63SDavid du Colombier  * with external power of 2, then binary search for the
378ccd4a63SDavid du Colombier  * closest mantissa to this decimal number.
388ccd4a63SDavid du Colombier  * Nmant is is the required precision. (53 for ieee dp)
398ccd4a63SDavid du Colombier  * Nbits is the max number of bits/word. (must be <= 28)
408ccd4a63SDavid du Colombier  * Prec is calculated - the number of words of fixed mantissa.
418ccd4a63SDavid du Colombier  */
428ccd4a63SDavid du Colombier enum
438ccd4a63SDavid du Colombier {
44*0d601874SDavid du Colombier 	Nbits	= 28,				/* bits safely represented in a ulong */
45*0d601874SDavid du Colombier 	Nmant	= 53,				/* bits of precision required */
46*0d601874SDavid du Colombier 	Prec	= (Nmant+Nbits+1)/Nbits,	/* words of Nbits each to represent mantissa */
47*0d601874SDavid du Colombier 	Sigbit	= 1<<(Prec*Nbits-Nmant),	/* first significant bit of Prec-th word */
488ccd4a63SDavid du Colombier 	Ndig	= 1500,
498ccd4a63SDavid du Colombier 	One	= (ulong)(1<<Nbits),
508ccd4a63SDavid du Colombier 	Half	= (ulong)(One>>1),
518ccd4a63SDavid du Colombier 	Maxe	= 310,
528ccd4a63SDavid du Colombier 
53*0d601874SDavid du Colombier 	Fsign	= 1<<0,		/* found - */
54*0d601874SDavid du Colombier 	Fesign	= 1<<1,		/* found e- */
55*0d601874SDavid du Colombier 	Fdpoint	= 1<<2,		/* found . */
56*0d601874SDavid du Colombier 
57*0d601874SDavid du Colombier 	S0	= 0,		/* _		_S0	+S1	#S2	.S3 */
58*0d601874SDavid du Colombier 	S1,			/* _+		#S2	.S3 */
59*0d601874SDavid du Colombier 	S2,			/* _+#		#S2	.S4	eS5 */
60*0d601874SDavid du Colombier 	S3,			/* _+.		#S4 */
61*0d601874SDavid du Colombier 	S4,			/* _+#.#	#S4	eS5 */
62*0d601874SDavid du Colombier 	S5,			/* _+#.#e	+S6	#S7 */
63*0d601874SDavid du Colombier 	S6,			/* _+#.#e+	#S7 */
64*0d601874SDavid du Colombier 	S7,			/* _+#.#e+#	#S7 */
658ccd4a63SDavid du Colombier };
668ccd4a63SDavid du Colombier 
678ccd4a63SDavid du Colombier static	int	xcmp(char*, char*);
688ccd4a63SDavid du Colombier static	int	fpcmp(char*, ulong*);
698ccd4a63SDavid du Colombier static	void	frnorm(ulong*);
708ccd4a63SDavid du Colombier static	void	divascii(char*, int*, int*, int*);
718ccd4a63SDavid du Colombier static	void	mulascii(char*, int*, int*, int*);
728ccd4a63SDavid du Colombier 
738ccd4a63SDavid du Colombier typedef	struct	Tab	Tab;
748ccd4a63SDavid du Colombier struct	Tab
758ccd4a63SDavid du Colombier {
768ccd4a63SDavid du Colombier 	int	bp;
778ccd4a63SDavid du Colombier 	int	siz;
788ccd4a63SDavid du Colombier 	char*	cmp;
798ccd4a63SDavid du Colombier };
808ccd4a63SDavid du Colombier 
818ccd4a63SDavid du Colombier double
82*0d601874SDavid du Colombier fmtstrtod(const char *as, char **aas)
838ccd4a63SDavid du Colombier {
84*0d601874SDavid du Colombier 	int na, ex, dp, bp, c, i, flag, state;
85*0d601874SDavid du Colombier 	ulong low[Prec], hig[Prec], mid[Prec];
868ccd4a63SDavid du Colombier 	double d;
878ccd4a63SDavid du Colombier 	char *s, a[Ndig];
888ccd4a63SDavid du Colombier 
89*0d601874SDavid du Colombier 	flag = 0;	/* Fsign, Fesign, Fdpoint */
90*0d601874SDavid du Colombier 	na = 0;		/* number of digits of a[] */
91*0d601874SDavid du Colombier 	dp = 0;		/* na of decimal point */
92*0d601874SDavid du Colombier 	ex = 0;		/* exonent */
938ccd4a63SDavid du Colombier 
948ccd4a63SDavid du Colombier 	state = S0;
95*0d601874SDavid du Colombier 	for(s=(char*)as;; s++) {
968ccd4a63SDavid du Colombier 		c = *s;
978ccd4a63SDavid du Colombier 		if(c >= '0' && c <= '9') {
988ccd4a63SDavid du Colombier 			switch(state) {
998ccd4a63SDavid du Colombier 			case S0:
1008ccd4a63SDavid du Colombier 			case S1:
1018ccd4a63SDavid du Colombier 			case S2:
1028ccd4a63SDavid du Colombier 				state = S2;
1038ccd4a63SDavid du Colombier 				break;
1048ccd4a63SDavid du Colombier 			case S3:
1058ccd4a63SDavid du Colombier 			case S4:
1068ccd4a63SDavid du Colombier 				state = S4;
1078ccd4a63SDavid du Colombier 				break;
1088ccd4a63SDavid du Colombier 
1098ccd4a63SDavid du Colombier 			case S5:
1108ccd4a63SDavid du Colombier 			case S6:
1118ccd4a63SDavid du Colombier 			case S7:
1128ccd4a63SDavid du Colombier 				state = S7;
1138ccd4a63SDavid du Colombier 				ex = ex*10 + (c-'0');
1148ccd4a63SDavid du Colombier 				continue;
1158ccd4a63SDavid du Colombier 			}
1168ccd4a63SDavid du Colombier 			if(na == 0 && c == '0') {
1178ccd4a63SDavid du Colombier 				dp--;
1188ccd4a63SDavid du Colombier 				continue;
1198ccd4a63SDavid du Colombier 			}
1208ccd4a63SDavid du Colombier 			if(na < Ndig-50)
1218ccd4a63SDavid du Colombier 				a[na++] = c;
1228ccd4a63SDavid du Colombier 			continue;
1238ccd4a63SDavid du Colombier 		}
1248ccd4a63SDavid du Colombier 		switch(c) {
1258ccd4a63SDavid du Colombier 		case '\t':
1268ccd4a63SDavid du Colombier 		case '\n':
1278ccd4a63SDavid du Colombier 		case '\v':
1288ccd4a63SDavid du Colombier 		case '\f':
1298ccd4a63SDavid du Colombier 		case '\r':
1308ccd4a63SDavid du Colombier 		case ' ':
1318ccd4a63SDavid du Colombier 			if(state == S0)
1328ccd4a63SDavid du Colombier 				continue;
1338ccd4a63SDavid du Colombier 			break;
1348ccd4a63SDavid du Colombier 		case '-':
1358ccd4a63SDavid du Colombier 			if(state == S0)
1368ccd4a63SDavid du Colombier 				flag |= Fsign;
1378ccd4a63SDavid du Colombier 			else
1388ccd4a63SDavid du Colombier 				flag |= Fesign;
1398ccd4a63SDavid du Colombier 		case '+':
1408ccd4a63SDavid du Colombier 			if(state == S0)
1418ccd4a63SDavid du Colombier 				state = S1;
1428ccd4a63SDavid du Colombier 			else
1438ccd4a63SDavid du Colombier 			if(state == S5)
1448ccd4a63SDavid du Colombier 				state = S6;
1458ccd4a63SDavid du Colombier 			else
146*0d601874SDavid du Colombier 				break;	/* syntax */
1478ccd4a63SDavid du Colombier 			continue;
1488ccd4a63SDavid du Colombier 		case '.':
1498ccd4a63SDavid du Colombier 			flag |= Fdpoint;
1508ccd4a63SDavid du Colombier 			dp = na;
1518ccd4a63SDavid du Colombier 			if(state == S0 || state == S1) {
1528ccd4a63SDavid du Colombier 				state = S3;
1538ccd4a63SDavid du Colombier 				continue;
1548ccd4a63SDavid du Colombier 			}
1558ccd4a63SDavid du Colombier 			if(state == S2) {
1568ccd4a63SDavid du Colombier 				state = S4;
1578ccd4a63SDavid du Colombier 				continue;
1588ccd4a63SDavid du Colombier 			}
1598ccd4a63SDavid du Colombier 			break;
1608ccd4a63SDavid du Colombier 		case 'e':
1618ccd4a63SDavid du Colombier 		case 'E':
1628ccd4a63SDavid du Colombier 			if(state == S2 || state == S4) {
1638ccd4a63SDavid du Colombier 				state = S5;
1648ccd4a63SDavid du Colombier 				continue;
1658ccd4a63SDavid du Colombier 			}
1668ccd4a63SDavid du Colombier 			break;
1678ccd4a63SDavid du Colombier 		}
1688ccd4a63SDavid du Colombier 		break;
1698ccd4a63SDavid du Colombier 	}
1708ccd4a63SDavid du Colombier 
1718ccd4a63SDavid du Colombier 	/*
1728ccd4a63SDavid du Colombier 	 * clean up return char-pointer
1738ccd4a63SDavid du Colombier 	 */
1748ccd4a63SDavid du Colombier 	switch(state) {
1758ccd4a63SDavid du Colombier 	case S0:
1768ccd4a63SDavid du Colombier 		if(xcmp(s, "nan") == 0) {
1778ccd4a63SDavid du Colombier 			if(aas != nil)
1788ccd4a63SDavid du Colombier 				*aas = s+3;
1798ccd4a63SDavid du Colombier 			goto retnan;
1808ccd4a63SDavid du Colombier 		}
1818ccd4a63SDavid du Colombier 	case S1:
1828ccd4a63SDavid du Colombier 		if(xcmp(s, "infinity") == 0) {
1838ccd4a63SDavid du Colombier 			if(aas != nil)
1848ccd4a63SDavid du Colombier 				*aas = s+8;
1858ccd4a63SDavid du Colombier 			goto retinf;
1868ccd4a63SDavid du Colombier 		}
1878ccd4a63SDavid du Colombier 		if(xcmp(s, "inf") == 0) {
1888ccd4a63SDavid du Colombier 			if(aas != nil)
1898ccd4a63SDavid du Colombier 				*aas = s+3;
1908ccd4a63SDavid du Colombier 			goto retinf;
1918ccd4a63SDavid du Colombier 		}
1928ccd4a63SDavid du Colombier 	case S3:
1938ccd4a63SDavid du Colombier 		if(aas != nil)
194*0d601874SDavid du Colombier 			*aas = (char*)as;
195*0d601874SDavid du Colombier 		goto ret0;	/* no digits found */
1968ccd4a63SDavid du Colombier 	case S6:
197*0d601874SDavid du Colombier 		s--;		/* back over +- */
1988ccd4a63SDavid du Colombier 	case S5:
199*0d601874SDavid du Colombier 		s--;		/* back over e */
2008ccd4a63SDavid du Colombier 		break;
2018ccd4a63SDavid du Colombier 	}
2028ccd4a63SDavid du Colombier 	if(aas != nil)
2038ccd4a63SDavid du Colombier 		*aas = s;
2048ccd4a63SDavid du Colombier 
2058ccd4a63SDavid du Colombier 	if(flag & Fdpoint)
2068ccd4a63SDavid du Colombier 	while(na > 0 && a[na-1] == '0')
2078ccd4a63SDavid du Colombier 		na--;
2088ccd4a63SDavid du Colombier 	if(na == 0)
209*0d601874SDavid du Colombier 		goto ret0;	/* zero */
2108ccd4a63SDavid du Colombier 	a[na] = 0;
2118ccd4a63SDavid du Colombier 	if(!(flag & Fdpoint))
2128ccd4a63SDavid du Colombier 		dp = na;
2138ccd4a63SDavid du Colombier 	if(flag & Fesign)
2148ccd4a63SDavid du Colombier 		ex = -ex;
2158ccd4a63SDavid du Colombier 	dp += ex;
216*0d601874SDavid du Colombier 	if(dp < -Maxe){
217*0d601874SDavid du Colombier 		errno = ERANGE;
218*0d601874SDavid du Colombier 		goto ret0;	/* underflow by exp */
219*0d601874SDavid du Colombier 	} else
2208ccd4a63SDavid du Colombier 	if(dp > +Maxe)
221*0d601874SDavid du Colombier 		goto retinf;	/* overflow by exp */
2228ccd4a63SDavid du Colombier 
2238ccd4a63SDavid du Colombier 	/*
2248ccd4a63SDavid du Colombier 	 * normalize the decimal ascii number
2258ccd4a63SDavid du Colombier 	 * to range .[5-9][0-9]* e0
2268ccd4a63SDavid du Colombier 	 */
227*0d601874SDavid du Colombier 	bp = 0;		/* binary exponent */
2288ccd4a63SDavid du Colombier 	while(dp > 0)
2298ccd4a63SDavid du Colombier 		divascii(a, &na, &dp, &bp);
2308ccd4a63SDavid du Colombier 	while(dp < 0 || a[0] < '5')
2318ccd4a63SDavid du Colombier 		mulascii(a, &na, &dp, &bp);
2328ccd4a63SDavid du Colombier 
2338ccd4a63SDavid du Colombier 	/* close approx by naive conversion */
234*0d601874SDavid du Colombier 	mid[0] = 0;
235*0d601874SDavid du Colombier 	mid[1] = 1;
236*0d601874SDavid du Colombier 	for(i=0; c=a[i]; i++) {
237*0d601874SDavid du Colombier 		mid[0] = mid[0]*10 + (c-'0');
238*0d601874SDavid du Colombier 		mid[1] = mid[1]*10;
239*0d601874SDavid du Colombier 		if(i >= 8)
240*0d601874SDavid du Colombier 			break;
2418ccd4a63SDavid du Colombier 	}
242*0d601874SDavid du Colombier 	low[0] = umuldiv(mid[0], One, mid[1]);
243*0d601874SDavid du Colombier 	hig[0] = umuldiv(mid[0]+1, One, mid[1]);
2448ccd4a63SDavid du Colombier 	for(i=1; i<Prec; i++) {
2458ccd4a63SDavid du Colombier 		low[i] = 0;
2468ccd4a63SDavid du Colombier 		hig[i] = One-1;
2478ccd4a63SDavid du Colombier 	}
2488ccd4a63SDavid du Colombier 
2498ccd4a63SDavid du Colombier 	/* binary search for closest mantissa */
2508ccd4a63SDavid du Colombier 	for(;;) {
2518ccd4a63SDavid du Colombier 		/* mid = (hig + low) / 2 */
2528ccd4a63SDavid du Colombier 		c = 0;
2538ccd4a63SDavid du Colombier 		for(i=0; i<Prec; i++) {
2548ccd4a63SDavid du Colombier 			mid[i] = hig[i] + low[i];
2558ccd4a63SDavid du Colombier 			if(c)
2568ccd4a63SDavid du Colombier 				mid[i] += One;
2578ccd4a63SDavid du Colombier 			c = mid[i] & 1;
2588ccd4a63SDavid du Colombier 			mid[i] >>= 1;
2598ccd4a63SDavid du Colombier 		}
2608ccd4a63SDavid du Colombier 		frnorm(mid);
2618ccd4a63SDavid du Colombier 
2628ccd4a63SDavid du Colombier 		/* compare */
2638ccd4a63SDavid du Colombier 		c = fpcmp(a, mid);
2648ccd4a63SDavid du Colombier 		if(c > 0) {
2658ccd4a63SDavid du Colombier 			c = 1;
2668ccd4a63SDavid du Colombier 			for(i=0; i<Prec; i++)
2678ccd4a63SDavid du Colombier 				if(low[i] != mid[i]) {
2688ccd4a63SDavid du Colombier 					c = 0;
2698ccd4a63SDavid du Colombier 					low[i] = mid[i];
2708ccd4a63SDavid du Colombier 				}
2718ccd4a63SDavid du Colombier 			if(c)
272*0d601874SDavid du Colombier 				break;	/* between mid and hig */
2738ccd4a63SDavid du Colombier 			continue;
2748ccd4a63SDavid du Colombier 		}
2758ccd4a63SDavid du Colombier 		if(c < 0) {
2768ccd4a63SDavid du Colombier 			for(i=0; i<Prec; i++)
2778ccd4a63SDavid du Colombier 				hig[i] = mid[i];
2788ccd4a63SDavid du Colombier 			continue;
2798ccd4a63SDavid du Colombier 		}
2808ccd4a63SDavid du Colombier 
2818ccd4a63SDavid du Colombier 		/* only hard part is if even/odd roundings wants to go up */
2828ccd4a63SDavid du Colombier 		c = mid[Prec-1] & (Sigbit-1);
2838ccd4a63SDavid du Colombier 		if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
2848ccd4a63SDavid du Colombier 			mid[Prec-1] -= c;
285*0d601874SDavid du Colombier 		break;	/* exactly mid */
2868ccd4a63SDavid du Colombier 	}
2878ccd4a63SDavid du Colombier 
2888ccd4a63SDavid du Colombier 	/* normal rounding applies */
2898ccd4a63SDavid du Colombier 	c = mid[Prec-1] & (Sigbit-1);
2908ccd4a63SDavid du Colombier 	mid[Prec-1] -= c;
2918ccd4a63SDavid du Colombier 	if(c >= Sigbit/2) {
2928ccd4a63SDavid du Colombier 		mid[Prec-1] += Sigbit;
2938ccd4a63SDavid du Colombier 		frnorm(mid);
2948ccd4a63SDavid du Colombier 	}
295*0d601874SDavid du Colombier 	goto out;
2968ccd4a63SDavid du Colombier 
2978ccd4a63SDavid du Colombier ret0:
2988ccd4a63SDavid du Colombier 	return 0;
2998ccd4a63SDavid du Colombier 
3008ccd4a63SDavid du Colombier retnan:
3018ccd4a63SDavid du Colombier 	return __NaN();
3028ccd4a63SDavid du Colombier 
3038ccd4a63SDavid du Colombier retinf:
304*0d601874SDavid du Colombier 	/*
305*0d601874SDavid du Colombier 	 * Unix strtod requires these.  Plan 9 would return Inf(0) or Inf(-1). */
306*0d601874SDavid du Colombier 	errno = ERANGE;
3078ccd4a63SDavid du Colombier 	if(flag & Fsign)
308*0d601874SDavid du Colombier 		return -HUGE_VAL;
309*0d601874SDavid du Colombier 	return HUGE_VAL;
310*0d601874SDavid du Colombier 
311*0d601874SDavid du Colombier out:
312*0d601874SDavid du Colombier 	d = 0;
313*0d601874SDavid du Colombier 	for(i=0; i<Prec; i++)
314*0d601874SDavid du Colombier 		d = d*One + mid[i];
315*0d601874SDavid du Colombier 	if(flag & Fsign)
316*0d601874SDavid du Colombier 		d = -d;
317*0d601874SDavid du Colombier 	d = ldexp(d, bp - Prec*Nbits);
318*0d601874SDavid du Colombier 	if(d == 0){	/* underflow */
319*0d601874SDavid du Colombier 		errno = ERANGE;
320*0d601874SDavid du Colombier 	}
321*0d601874SDavid du Colombier 	return d;
3228ccd4a63SDavid du Colombier }
3238ccd4a63SDavid du Colombier 
3248ccd4a63SDavid du Colombier static void
3258ccd4a63SDavid du Colombier frnorm(ulong *f)
3268ccd4a63SDavid du Colombier {
3278ccd4a63SDavid du Colombier 	int i, c;
3288ccd4a63SDavid du Colombier 
3298ccd4a63SDavid du Colombier 	c = 0;
3308ccd4a63SDavid du Colombier 	for(i=Prec-1; i>0; i--) {
3318ccd4a63SDavid du Colombier 		f[i] += c;
3328ccd4a63SDavid du Colombier 		c = f[i] >> Nbits;
3338ccd4a63SDavid du Colombier 		f[i] &= One-1;
3348ccd4a63SDavid du Colombier 	}
3358ccd4a63SDavid du Colombier 	f[0] += c;
3368ccd4a63SDavid du Colombier }
3378ccd4a63SDavid du Colombier 
3388ccd4a63SDavid du Colombier static int
3398ccd4a63SDavid du Colombier fpcmp(char *a, ulong* f)
3408ccd4a63SDavid du Colombier {
3418ccd4a63SDavid du Colombier 	ulong tf[Prec];
3428ccd4a63SDavid du Colombier 	int i, d, c;
3438ccd4a63SDavid du Colombier 
3448ccd4a63SDavid du Colombier 	for(i=0; i<Prec; i++)
3458ccd4a63SDavid du Colombier 		tf[i] = f[i];
3468ccd4a63SDavid du Colombier 
3478ccd4a63SDavid du Colombier 	for(;;) {
3488ccd4a63SDavid du Colombier 		/* tf *= 10 */
3498ccd4a63SDavid du Colombier 		for(i=0; i<Prec; i++)
3508ccd4a63SDavid du Colombier 			tf[i] = tf[i]*10;
3518ccd4a63SDavid du Colombier 		frnorm(tf);
3528ccd4a63SDavid du Colombier 		d = (tf[0] >> Nbits) + '0';
3538ccd4a63SDavid du Colombier 		tf[0] &= One-1;
3548ccd4a63SDavid du Colombier 
3558ccd4a63SDavid du Colombier 		/* compare next digit */
3568ccd4a63SDavid du Colombier 		c = *a;
3578ccd4a63SDavid du Colombier 		if(c == 0) {
3588ccd4a63SDavid du Colombier 			if('0' < d)
3598ccd4a63SDavid du Colombier 				return -1;
3608ccd4a63SDavid du Colombier 			if(tf[0] != 0)
3618ccd4a63SDavid du Colombier 				goto cont;
3628ccd4a63SDavid du Colombier 			for(i=1; i<Prec; i++)
3638ccd4a63SDavid du Colombier 				if(tf[i] != 0)
3648ccd4a63SDavid du Colombier 					goto cont;
3658ccd4a63SDavid du Colombier 			return 0;
3668ccd4a63SDavid du Colombier 		}
3678ccd4a63SDavid du Colombier 		if(c > d)
3688ccd4a63SDavid du Colombier 			return +1;
3698ccd4a63SDavid du Colombier 		if(c < d)
3708ccd4a63SDavid du Colombier 			return -1;
3718ccd4a63SDavid du Colombier 		a++;
3728ccd4a63SDavid du Colombier 	cont:;
3738ccd4a63SDavid du Colombier 	}
3748ccd4a63SDavid du Colombier }
3758ccd4a63SDavid du Colombier 
3768ccd4a63SDavid du Colombier static void
377*0d601874SDavid du Colombier divby(char *a, int *na, int b)
3788ccd4a63SDavid du Colombier {
3798ccd4a63SDavid du Colombier 	int n, c;
3808ccd4a63SDavid du Colombier 	char *p;
3818ccd4a63SDavid du Colombier 
3828ccd4a63SDavid du Colombier 	p = a;
3838ccd4a63SDavid du Colombier 	n = 0;
3848ccd4a63SDavid du Colombier 	while(n>>b == 0) {
3858ccd4a63SDavid du Colombier 		c = *a++;
3868ccd4a63SDavid du Colombier 		if(c == 0) {
3878ccd4a63SDavid du Colombier 			while(n) {
3888ccd4a63SDavid du Colombier 				c = n*10;
3898ccd4a63SDavid du Colombier 				if(c>>b)
3908ccd4a63SDavid du Colombier 					break;
3918ccd4a63SDavid du Colombier 				n = c;
3928ccd4a63SDavid du Colombier 			}
3938ccd4a63SDavid du Colombier 			goto xx;
3948ccd4a63SDavid du Colombier 		}
3958ccd4a63SDavid du Colombier 		n = n*10 + c-'0';
3968ccd4a63SDavid du Colombier 		(*na)--;
3978ccd4a63SDavid du Colombier 	}
3988ccd4a63SDavid du Colombier 	for(;;) {
3998ccd4a63SDavid du Colombier 		c = n>>b;
4008ccd4a63SDavid du Colombier 		n -= c<<b;
4018ccd4a63SDavid du Colombier 		*p++ = c + '0';
4028ccd4a63SDavid du Colombier 		c = *a++;
4038ccd4a63SDavid du Colombier 		if(c == 0)
4048ccd4a63SDavid du Colombier 			break;
4058ccd4a63SDavid du Colombier 		n = n*10 + c-'0';
4068ccd4a63SDavid du Colombier 	}
4078ccd4a63SDavid du Colombier 	(*na)++;
4088ccd4a63SDavid du Colombier xx:
4098ccd4a63SDavid du Colombier 	while(n) {
4108ccd4a63SDavid du Colombier 		n = n*10;
4118ccd4a63SDavid du Colombier 		c = n>>b;
4128ccd4a63SDavid du Colombier 		n -= c<<b;
4138ccd4a63SDavid du Colombier 		*p++ = c + '0';
4148ccd4a63SDavid du Colombier 		(*na)++;
4158ccd4a63SDavid du Colombier 	}
4168ccd4a63SDavid du Colombier 	*p = 0;
4178ccd4a63SDavid du Colombier }
4188ccd4a63SDavid du Colombier 
4198ccd4a63SDavid du Colombier static	Tab	tab1[] =
4208ccd4a63SDavid du Colombier {
4218ccd4a63SDavid du Colombier 	 1,  0, "",
4228ccd4a63SDavid du Colombier 	 3,  1, "7",
4238ccd4a63SDavid du Colombier 	 6,  2, "63",
4248ccd4a63SDavid du Colombier 	 9,  3, "511",
4258ccd4a63SDavid du Colombier 	13,  4, "8191",
4268ccd4a63SDavid du Colombier 	16,  5, "65535",
4278ccd4a63SDavid du Colombier 	19,  6, "524287",
4288ccd4a63SDavid du Colombier 	23,  7, "8388607",
4298ccd4a63SDavid du Colombier 	26,  8, "67108863",
4308ccd4a63SDavid du Colombier 	27,  9, "134217727",
4318ccd4a63SDavid du Colombier };
4328ccd4a63SDavid du Colombier 
4338ccd4a63SDavid du Colombier static void
4348ccd4a63SDavid du Colombier divascii(char *a, int *na, int *dp, int *bp)
4358ccd4a63SDavid du Colombier {
4368ccd4a63SDavid du Colombier 	int b, d;
4378ccd4a63SDavid du Colombier 	Tab *t;
4388ccd4a63SDavid du Colombier 
4398ccd4a63SDavid du Colombier 	d = *dp;
440*0d601874SDavid du Colombier 	if(d >= (int)(nelem(tab1)))
441*0d601874SDavid du Colombier 		d = (int)(nelem(tab1))-1;
4428ccd4a63SDavid du Colombier 	t = tab1 + d;
4438ccd4a63SDavid du Colombier 	b = t->bp;
4448ccd4a63SDavid du Colombier 	if(memcmp(a, t->cmp, t->siz) > 0)
4458ccd4a63SDavid du Colombier 		d--;
4468ccd4a63SDavid du Colombier 	*dp -= d;
4478ccd4a63SDavid du Colombier 	*bp += b;
4488ccd4a63SDavid du Colombier 	divby(a, na, b);
4498ccd4a63SDavid du Colombier }
4508ccd4a63SDavid du Colombier 
4518ccd4a63SDavid du Colombier static void
4528ccd4a63SDavid du Colombier mulby(char *a, char *p, char *q, int b)
4538ccd4a63SDavid du Colombier {
4548ccd4a63SDavid du Colombier 	int n, c;
4558ccd4a63SDavid du Colombier 
4568ccd4a63SDavid du Colombier 	n = 0;
4578ccd4a63SDavid du Colombier 	*p = 0;
4588ccd4a63SDavid du Colombier 	for(;;) {
4598ccd4a63SDavid du Colombier 		q--;
4608ccd4a63SDavid du Colombier 		if(q < a)
4618ccd4a63SDavid du Colombier 			break;
4628ccd4a63SDavid du Colombier 		c = *q - '0';
4638ccd4a63SDavid du Colombier 		c = (c<<b) + n;
4648ccd4a63SDavid du Colombier 		n = c/10;
4658ccd4a63SDavid du Colombier 		c -= n*10;
4668ccd4a63SDavid du Colombier 		p--;
4678ccd4a63SDavid du Colombier 		*p = c + '0';
4688ccd4a63SDavid du Colombier 	}
4698ccd4a63SDavid du Colombier 	while(n) {
4708ccd4a63SDavid du Colombier 		c = n;
4718ccd4a63SDavid du Colombier 		n = c/10;
4728ccd4a63SDavid du Colombier 		c -= n*10;
4738ccd4a63SDavid du Colombier 		p--;
4748ccd4a63SDavid du Colombier 		*p = c + '0';
4758ccd4a63SDavid du Colombier 	}
4768ccd4a63SDavid du Colombier }
4778ccd4a63SDavid du Colombier 
4788ccd4a63SDavid du Colombier static	Tab	tab2[] =
4798ccd4a63SDavid du Colombier {
480*0d601874SDavid du Colombier 	 1,  1, "",				/* dp = 0-0 */
4818ccd4a63SDavid du Colombier 	 3,  3, "125",
4828ccd4a63SDavid du Colombier 	 6,  5, "15625",
4838ccd4a63SDavid du Colombier 	 9,  7, "1953125",
4848ccd4a63SDavid du Colombier 	13, 10, "1220703125",
4858ccd4a63SDavid du Colombier 	16, 12, "152587890625",
4868ccd4a63SDavid du Colombier 	19, 14, "19073486328125",
4878ccd4a63SDavid du Colombier 	23, 17, "11920928955078125",
4888ccd4a63SDavid du Colombier 	26, 19, "1490116119384765625",
489*0d601874SDavid du Colombier 	27, 19, "7450580596923828125",		/* dp 8-9 */
4908ccd4a63SDavid du Colombier };
4918ccd4a63SDavid du Colombier 
4928ccd4a63SDavid du Colombier static void
4938ccd4a63SDavid du Colombier mulascii(char *a, int *na, int *dp, int *bp)
4948ccd4a63SDavid du Colombier {
4958ccd4a63SDavid du Colombier 	char *p;
4968ccd4a63SDavid du Colombier 	int d, b;
4978ccd4a63SDavid du Colombier 	Tab *t;
4988ccd4a63SDavid du Colombier 
4998ccd4a63SDavid du Colombier 	d = -*dp;
500*0d601874SDavid du Colombier 	if(d >= (int)(nelem(tab2)))
501*0d601874SDavid du Colombier 		d = (int)(nelem(tab2))-1;
5028ccd4a63SDavid du Colombier 	t = tab2 + d;
5038ccd4a63SDavid du Colombier 	b = t->bp;
5048ccd4a63SDavid du Colombier 	if(memcmp(a, t->cmp, t->siz) < 0)
5058ccd4a63SDavid du Colombier 		d--;
5068ccd4a63SDavid du Colombier 	p = a + *na;
5078ccd4a63SDavid du Colombier 	*bp -= b;
5088ccd4a63SDavid du Colombier 	*dp += d;
5098ccd4a63SDavid du Colombier 	*na += d;
5108ccd4a63SDavid du Colombier 	mulby(a, p+d, p, b);
5118ccd4a63SDavid du Colombier }
5128ccd4a63SDavid du Colombier 
5138ccd4a63SDavid du Colombier static int
5148ccd4a63SDavid du Colombier xcmp(char *a, char *b)
5158ccd4a63SDavid du Colombier {
5168ccd4a63SDavid du Colombier 	int c1, c2;
5178ccd4a63SDavid du Colombier 
5188ccd4a63SDavid du Colombier 	while((c1 = *b++)) {
5198ccd4a63SDavid du Colombier 		c2 = *a++;
5208ccd4a63SDavid du Colombier 		if(isupper(c2))
5218ccd4a63SDavid du Colombier 			c2 = tolower(c2);
5228ccd4a63SDavid du Colombier 		if(c1 != c2)
5238ccd4a63SDavid du Colombier 			return 1;
5248ccd4a63SDavid du Colombier 	}
5258ccd4a63SDavid du Colombier 	return 0;
5268ccd4a63SDavid du Colombier }
527