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