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