xref: /plan9/sys/src/libstdio/dtoa.c (revision eea45bbc7433324b1a128e781bea3583607d57fb)
159cc4ca5SDavid du Colombier /* derived from /netlib/fp/dtoa.c assuming IEEE, Standard C */
259cc4ca5SDavid du Colombier /* kudos to dmg@bell-labs.com, gripes to ehg@bell-labs.com */
359cc4ca5SDavid du Colombier 
459cc4ca5SDavid du Colombier /* Let x be the exact mathematical number defined by a decimal
559cc4ca5SDavid du Colombier  *	string s.  Then atof(s) is the round-nearest-even IEEE
659cc4ca5SDavid du Colombier  *	floating point value.
759cc4ca5SDavid du Colombier  * Let y be an IEEE floating point value and let s be the string
859cc4ca5SDavid du Colombier  *	printed as %.17g.  Then atof(s) is exactly y.
959cc4ca5SDavid du Colombier  */
1059cc4ca5SDavid du Colombier #include <u.h>
1159cc4ca5SDavid du Colombier #include <libc.h>
1259cc4ca5SDavid du Colombier 
1359cc4ca5SDavid du Colombier static Lock _dtoalk[2];
1459cc4ca5SDavid du Colombier #define ACQUIRE_DTOA_LOCK(n)	lock(&_dtoalk[n])
1559cc4ca5SDavid du Colombier #define FREE_DTOA_LOCK(n)	unlock(&_dtoalk[n])
168c242bd4SDavid du Colombier 
1759cc4ca5SDavid du Colombier #define PRIVATE_mem ((2000+sizeof(double)-1)/sizeof(double))
1859cc4ca5SDavid du Colombier static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
198c242bd4SDavid du Colombier 
2059cc4ca5SDavid du Colombier #define FLT_ROUNDS	1
2159cc4ca5SDavid du Colombier #define DBL_DIG		15
2259cc4ca5SDavid du Colombier #define DBL_MAX_10_EXP	308
2359cc4ca5SDavid du Colombier #define DBL_MAX_EXP	1024
2459cc4ca5SDavid du Colombier #define FLT_RADIX	2
2559cc4ca5SDavid du Colombier #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
268c242bd4SDavid du Colombier 
2759cc4ca5SDavid du Colombier /* Ten_pmax = floor(P*log(2)/log(5)) */
2859cc4ca5SDavid du Colombier /* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
2959cc4ca5SDavid du Colombier /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
3059cc4ca5SDavid du Colombier /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
3159cc4ca5SDavid du Colombier 
3259cc4ca5SDavid du Colombier #define Exp_shift  20
3359cc4ca5SDavid du Colombier #define Exp_shift1 20
3459cc4ca5SDavid du Colombier #define Exp_msk1    0x100000
3559cc4ca5SDavid du Colombier #define Exp_msk11   0x100000
3659cc4ca5SDavid du Colombier #define Exp_mask  0x7ff00000
3759cc4ca5SDavid du Colombier #define P 53
3859cc4ca5SDavid du Colombier #define Bias 1023
3959cc4ca5SDavid du Colombier #define Emin (-1022)
4059cc4ca5SDavid du Colombier #define Exp_1  0x3ff00000
4159cc4ca5SDavid du Colombier #define Exp_11 0x3ff00000
4259cc4ca5SDavid du Colombier #define Ebits 11
4359cc4ca5SDavid du Colombier #define Frac_mask  0xfffff
4459cc4ca5SDavid du Colombier #define Frac_mask1 0xfffff
4559cc4ca5SDavid du Colombier #define Ten_pmax 22
4659cc4ca5SDavid du Colombier #define Bletch 0x10
4759cc4ca5SDavid du Colombier #define Bndry_mask  0xfffff
4859cc4ca5SDavid du Colombier #define Bndry_mask1 0xfffff
4959cc4ca5SDavid du Colombier #define LSB 1
5059cc4ca5SDavid du Colombier #define Sign_bit 0x80000000
5159cc4ca5SDavid du Colombier #define Log2P 1
5259cc4ca5SDavid du Colombier #define Tiny0 0
5359cc4ca5SDavid du Colombier #define Tiny1 1
5459cc4ca5SDavid du Colombier #define Quick_max 14
5559cc4ca5SDavid du Colombier #define Int_max 14
5659cc4ca5SDavid du Colombier #define Avoid_Underflow
5759cc4ca5SDavid du Colombier 
5859cc4ca5SDavid du Colombier #define rounded_product(a,b) a *= b
5959cc4ca5SDavid du Colombier #define rounded_quotient(a,b) a /= b
6059cc4ca5SDavid du Colombier 
6159cc4ca5SDavid du Colombier #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
6259cc4ca5SDavid du Colombier #define Big1 0xffffffff
6359cc4ca5SDavid du Colombier 
6459cc4ca5SDavid du Colombier #define FFFFFFFF 0xffffffffUL
6559cc4ca5SDavid du Colombier 
6659cc4ca5SDavid du Colombier #define Kmax 15
6759cc4ca5SDavid du Colombier 
688c242bd4SDavid du Colombier typedef struct Bigint Bigint;
698c242bd4SDavid du Colombier typedef struct Ulongs Ulongs;
708c242bd4SDavid du Colombier 
718c242bd4SDavid du Colombier struct Bigint {
728c242bd4SDavid du Colombier 	Bigint *next;
7359cc4ca5SDavid du Colombier 	int	k, maxwds, sign, wds;
748c242bd4SDavid du Colombier 	unsigned x[1];
7559cc4ca5SDavid du Colombier };
7659cc4ca5SDavid du Colombier 
778c242bd4SDavid du Colombier struct Ulongs {
788c242bd4SDavid du Colombier 	ulong	hi;
798c242bd4SDavid du Colombier 	ulong	lo;
808c242bd4SDavid du Colombier };
8159cc4ca5SDavid du Colombier 
8259cc4ca5SDavid du Colombier static Bigint *freelist[Kmax+1];
8359cc4ca5SDavid du Colombier 
848c242bd4SDavid du Colombier Ulongs
double2ulongs(double d)858c242bd4SDavid du Colombier double2ulongs(double d)
868c242bd4SDavid du Colombier {
878c242bd4SDavid du Colombier 	FPdbleword dw;
888c242bd4SDavid du Colombier 	Ulongs uls;
898c242bd4SDavid du Colombier 
908c242bd4SDavid du Colombier 	dw.x = d;
918c242bd4SDavid du Colombier 	uls.hi = dw.hi;
928c242bd4SDavid du Colombier 	uls.lo = dw.lo;
938c242bd4SDavid du Colombier 	return uls;
948c242bd4SDavid du Colombier }
958c242bd4SDavid du Colombier 
968c242bd4SDavid du Colombier double
ulongs2double(Ulongs uls)978c242bd4SDavid du Colombier ulongs2double(Ulongs uls)
988c242bd4SDavid du Colombier {
998c242bd4SDavid du Colombier 	FPdbleword dw;
1008c242bd4SDavid du Colombier 
1018c242bd4SDavid du Colombier 	dw.hi = uls.hi;
1028c242bd4SDavid du Colombier 	dw.lo = uls.lo;
1038c242bd4SDavid du Colombier 	return dw.x;
1048c242bd4SDavid du Colombier }
1058c242bd4SDavid du Colombier 
10659cc4ca5SDavid du Colombier static Bigint *
Balloc(int k)10759cc4ca5SDavid du Colombier Balloc(int k)
10859cc4ca5SDavid du Colombier {
10959cc4ca5SDavid du Colombier 	int	x;
11059cc4ca5SDavid du Colombier 	Bigint * rv;
11159cc4ca5SDavid du Colombier 	unsigned int	len;
11259cc4ca5SDavid du Colombier 
11359cc4ca5SDavid du Colombier 	ACQUIRE_DTOA_LOCK(0);
11459cc4ca5SDavid du Colombier 	if (rv = freelist[k]) {
11559cc4ca5SDavid du Colombier 		freelist[k] = rv->next;
11659cc4ca5SDavid du Colombier 	} else {
11759cc4ca5SDavid du Colombier 		x = 1 << k;
11859cc4ca5SDavid du Colombier 		len = (sizeof(Bigint) + (x - 1) * sizeof(unsigned int) + sizeof(double) -1)
11959cc4ca5SDavid du Colombier 		 / sizeof(double);
12059cc4ca5SDavid du Colombier 		if (pmem_next - private_mem + len <= PRIVATE_mem) {
12159cc4ca5SDavid du Colombier 			rv = (Bigint * )pmem_next;
12259cc4ca5SDavid du Colombier 			pmem_next += len;
12359cc4ca5SDavid du Colombier 		} else
12459cc4ca5SDavid du Colombier 			rv = (Bigint * )malloc(len * sizeof(double));
12559cc4ca5SDavid du Colombier 		rv->k = k;
12659cc4ca5SDavid du Colombier 		rv->maxwds = x;
12759cc4ca5SDavid du Colombier 	}
12859cc4ca5SDavid du Colombier 	FREE_DTOA_LOCK(0);
12959cc4ca5SDavid du Colombier 	rv->sign = rv->wds = 0;
13059cc4ca5SDavid du Colombier 	return rv;
13159cc4ca5SDavid du Colombier }
13259cc4ca5SDavid du Colombier 
13359cc4ca5SDavid du Colombier static void
Bfree(Bigint * v)13459cc4ca5SDavid du Colombier Bfree(Bigint *v)
13559cc4ca5SDavid du Colombier {
13659cc4ca5SDavid du Colombier 	if (v) {
13759cc4ca5SDavid du Colombier 		ACQUIRE_DTOA_LOCK(0);
13859cc4ca5SDavid du Colombier 		v->next = freelist[v->k];
13959cc4ca5SDavid du Colombier 		freelist[v->k] = v;
14059cc4ca5SDavid du Colombier 		FREE_DTOA_LOCK(0);
14159cc4ca5SDavid du Colombier 	}
14259cc4ca5SDavid du Colombier }
14359cc4ca5SDavid du Colombier 
14459cc4ca5SDavid du Colombier #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
14559cc4ca5SDavid du Colombier y->wds*sizeof(int) + 2*sizeof(int))
14659cc4ca5SDavid du Colombier 
14759cc4ca5SDavid du Colombier static Bigint *
multadd(Bigint * b,int m,int a)14859cc4ca5SDavid du Colombier multadd(Bigint *b, int m, int a)	/* multiply by m and add a */
14959cc4ca5SDavid du Colombier {
15059cc4ca5SDavid du Colombier 	int	i, wds;
15159cc4ca5SDavid du Colombier 	unsigned int carry, *x, y;
15259cc4ca5SDavid du Colombier 	unsigned int xi, z;
15359cc4ca5SDavid du Colombier 	Bigint * b1;
15459cc4ca5SDavid du Colombier 
15559cc4ca5SDavid du Colombier 	wds = b->wds;
15659cc4ca5SDavid du Colombier 	x = b->x;
15759cc4ca5SDavid du Colombier 	i = 0;
15859cc4ca5SDavid du Colombier 	carry = a;
15959cc4ca5SDavid du Colombier 	do {
16059cc4ca5SDavid du Colombier 		xi = *x;
16159cc4ca5SDavid du Colombier 		y = (xi & 0xffff) * m + carry;
16259cc4ca5SDavid du Colombier 		z = (xi >> 16) * m + (y >> 16);
16359cc4ca5SDavid du Colombier 		carry = z >> 16;
16459cc4ca5SDavid du Colombier 		*x++ = (z << 16) + (y & 0xffff);
16559cc4ca5SDavid du Colombier 	} while (++i < wds);
16659cc4ca5SDavid du Colombier 	if (carry) {
16759cc4ca5SDavid du Colombier 		if (wds >= b->maxwds) {
16859cc4ca5SDavid du Colombier 			b1 = Balloc(b->k + 1);
16959cc4ca5SDavid du Colombier 			Bcopy(b1, b);
17059cc4ca5SDavid du Colombier 			Bfree(b);
17159cc4ca5SDavid du Colombier 			b = b1;
17259cc4ca5SDavid du Colombier 		}
17359cc4ca5SDavid du Colombier 		b->x[wds++] = carry;
17459cc4ca5SDavid du Colombier 		b->wds = wds;
17559cc4ca5SDavid du Colombier 	}
17659cc4ca5SDavid du Colombier 	return b;
17759cc4ca5SDavid du Colombier }
17859cc4ca5SDavid du Colombier 
17959cc4ca5SDavid du Colombier static Bigint *
s2b(const char * s,int nd0,int nd,unsigned int y9)18059cc4ca5SDavid du Colombier s2b(const char *s, int nd0, int nd, unsigned int y9)
18159cc4ca5SDavid du Colombier {
18259cc4ca5SDavid du Colombier 	Bigint * b;
18359cc4ca5SDavid du Colombier 	int	i, k;
18459cc4ca5SDavid du Colombier 	int x, y;
18559cc4ca5SDavid du Colombier 
18659cc4ca5SDavid du Colombier 	x = (nd + 8) / 9;
18759cc4ca5SDavid du Colombier 	for (k = 0, y = 1; x > y; y <<= 1, k++)
18859cc4ca5SDavid du Colombier 		;
18959cc4ca5SDavid du Colombier 	b = Balloc(k);
19059cc4ca5SDavid du Colombier 	b->x[0] = y9;
19159cc4ca5SDavid du Colombier 	b->wds = 1;
19259cc4ca5SDavid du Colombier 
19359cc4ca5SDavid du Colombier 	i = 9;
19459cc4ca5SDavid du Colombier 	if (9 < nd0) {
19559cc4ca5SDavid du Colombier 		s += 9;
19659cc4ca5SDavid du Colombier 		do
19759cc4ca5SDavid du Colombier 			b = multadd(b, 10, *s++ - '0');
19859cc4ca5SDavid du Colombier 		while (++i < nd0);
19959cc4ca5SDavid du Colombier 		s++;
20059cc4ca5SDavid du Colombier 	} else
20159cc4ca5SDavid du Colombier 		s += 10;
20259cc4ca5SDavid du Colombier 	for (; i < nd; i++)
20359cc4ca5SDavid du Colombier 		b = multadd(b, 10, *s++ - '0');
20459cc4ca5SDavid du Colombier 	return b;
20559cc4ca5SDavid du Colombier }
20659cc4ca5SDavid du Colombier 
20759cc4ca5SDavid du Colombier static int
hi0bits(register unsigned int x)20859cc4ca5SDavid du Colombier hi0bits(register unsigned int x)
20959cc4ca5SDavid du Colombier {
21059cc4ca5SDavid du Colombier 	register int	k = 0;
21159cc4ca5SDavid du Colombier 
21259cc4ca5SDavid du Colombier 	if (!(x & 0xffff0000)) {
21359cc4ca5SDavid du Colombier 		k = 16;
21459cc4ca5SDavid du Colombier 		x <<= 16;
21559cc4ca5SDavid du Colombier 	}
21659cc4ca5SDavid du Colombier 	if (!(x & 0xff000000)) {
21759cc4ca5SDavid du Colombier 		k += 8;
21859cc4ca5SDavid du Colombier 		x <<= 8;
21959cc4ca5SDavid du Colombier 	}
22059cc4ca5SDavid du Colombier 	if (!(x & 0xf0000000)) {
22159cc4ca5SDavid du Colombier 		k += 4;
22259cc4ca5SDavid du Colombier 		x <<= 4;
22359cc4ca5SDavid du Colombier 	}
22459cc4ca5SDavid du Colombier 	if (!(x & 0xc0000000)) {
22559cc4ca5SDavid du Colombier 		k += 2;
22659cc4ca5SDavid du Colombier 		x <<= 2;
22759cc4ca5SDavid du Colombier 	}
22859cc4ca5SDavid du Colombier 	if (!(x & 0x80000000)) {
22959cc4ca5SDavid du Colombier 		k++;
23059cc4ca5SDavid du Colombier 		if (!(x & 0x40000000))
23159cc4ca5SDavid du Colombier 			return 32;
23259cc4ca5SDavid du Colombier 	}
23359cc4ca5SDavid du Colombier 	return k;
23459cc4ca5SDavid du Colombier }
23559cc4ca5SDavid du Colombier 
23659cc4ca5SDavid du Colombier static int
lo0bits(unsigned int * y)23759cc4ca5SDavid du Colombier lo0bits(unsigned int *y)
23859cc4ca5SDavid du Colombier {
23959cc4ca5SDavid du Colombier 	register int	k;
24059cc4ca5SDavid du Colombier 	register unsigned int x = *y;
24159cc4ca5SDavid du Colombier 
24259cc4ca5SDavid du Colombier 	if (x & 7) {
24359cc4ca5SDavid du Colombier 		if (x & 1)
24459cc4ca5SDavid du Colombier 			return 0;
24559cc4ca5SDavid du Colombier 		if (x & 2) {
24659cc4ca5SDavid du Colombier 			*y = x >> 1;
24759cc4ca5SDavid du Colombier 			return 1;
24859cc4ca5SDavid du Colombier 		}
24959cc4ca5SDavid du Colombier 		*y = x >> 2;
25059cc4ca5SDavid du Colombier 		return 2;
25159cc4ca5SDavid du Colombier 	}
25259cc4ca5SDavid du Colombier 	k = 0;
25359cc4ca5SDavid du Colombier 	if (!(x & 0xffff)) {
25459cc4ca5SDavid du Colombier 		k = 16;
25559cc4ca5SDavid du Colombier 		x >>= 16;
25659cc4ca5SDavid du Colombier 	}
25759cc4ca5SDavid du Colombier 	if (!(x & 0xff)) {
25859cc4ca5SDavid du Colombier 		k += 8;
25959cc4ca5SDavid du Colombier 		x >>= 8;
26059cc4ca5SDavid du Colombier 	}
26159cc4ca5SDavid du Colombier 	if (!(x & 0xf)) {
26259cc4ca5SDavid du Colombier 		k += 4;
26359cc4ca5SDavid du Colombier 		x >>= 4;
26459cc4ca5SDavid du Colombier 	}
26559cc4ca5SDavid du Colombier 	if (!(x & 0x3)) {
26659cc4ca5SDavid du Colombier 		k += 2;
26759cc4ca5SDavid du Colombier 		x >>= 2;
26859cc4ca5SDavid du Colombier 	}
26959cc4ca5SDavid du Colombier 	if (!(x & 1)) {
27059cc4ca5SDavid du Colombier 		k++;
27159cc4ca5SDavid du Colombier 		x >>= 1;
27259cc4ca5SDavid du Colombier 		if (!x & 1)
27359cc4ca5SDavid du Colombier 			return 32;
27459cc4ca5SDavid du Colombier 	}
27559cc4ca5SDavid du Colombier 	*y = x;
27659cc4ca5SDavid du Colombier 	return k;
27759cc4ca5SDavid du Colombier }
27859cc4ca5SDavid du Colombier 
27959cc4ca5SDavid du Colombier static Bigint *
i2b(int i)28059cc4ca5SDavid du Colombier i2b(int i)
28159cc4ca5SDavid du Colombier {
28259cc4ca5SDavid du Colombier 	Bigint * b;
28359cc4ca5SDavid du Colombier 
28459cc4ca5SDavid du Colombier 	b = Balloc(1);
28559cc4ca5SDavid du Colombier 	b->x[0] = i;
28659cc4ca5SDavid du Colombier 	b->wds = 1;
28759cc4ca5SDavid du Colombier 	return b;
28859cc4ca5SDavid du Colombier }
28959cc4ca5SDavid du Colombier 
29059cc4ca5SDavid du Colombier static Bigint *
mult(Bigint * a,Bigint * b)29159cc4ca5SDavid du Colombier mult(Bigint *a, Bigint *b)
29259cc4ca5SDavid du Colombier {
29359cc4ca5SDavid du Colombier 	Bigint * c;
29459cc4ca5SDavid du Colombier 	int	k, wa, wb, wc;
29559cc4ca5SDavid du Colombier 	unsigned int * x, *xa, *xae, *xb, *xbe, *xc, *xc0;
29659cc4ca5SDavid du Colombier 	unsigned int y;
29759cc4ca5SDavid du Colombier 	unsigned int carry, z;
29859cc4ca5SDavid du Colombier 	unsigned int z2;
29959cc4ca5SDavid du Colombier 
30059cc4ca5SDavid du Colombier 	if (a->wds < b->wds) {
30159cc4ca5SDavid du Colombier 		c = a;
30259cc4ca5SDavid du Colombier 		a = b;
30359cc4ca5SDavid du Colombier 		b = c;
30459cc4ca5SDavid du Colombier 	}
30559cc4ca5SDavid du Colombier 	k = a->k;
30659cc4ca5SDavid du Colombier 	wa = a->wds;
30759cc4ca5SDavid du Colombier 	wb = b->wds;
30859cc4ca5SDavid du Colombier 	wc = wa + wb;
30959cc4ca5SDavid du Colombier 	if (wc > a->maxwds)
31059cc4ca5SDavid du Colombier 		k++;
31159cc4ca5SDavid du Colombier 	c = Balloc(k);
31259cc4ca5SDavid du Colombier 	for (x = c->x, xa = x + wc; x < xa; x++)
31359cc4ca5SDavid du Colombier 		*x = 0;
31459cc4ca5SDavid du Colombier 	xa = a->x;
31559cc4ca5SDavid du Colombier 	xae = xa + wa;
31659cc4ca5SDavid du Colombier 	xb = b->x;
31759cc4ca5SDavid du Colombier 	xbe = xb + wb;
31859cc4ca5SDavid du Colombier 	xc0 = c->x;
31959cc4ca5SDavid du Colombier 	for (; xb < xbe; xb++, xc0++) {
32059cc4ca5SDavid du Colombier 		if (y = *xb & 0xffff) {
32159cc4ca5SDavid du Colombier 			x = xa;
32259cc4ca5SDavid du Colombier 			xc = xc0;
32359cc4ca5SDavid du Colombier 			carry = 0;
32459cc4ca5SDavid du Colombier 			do {
32559cc4ca5SDavid du Colombier 				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
32659cc4ca5SDavid du Colombier 				carry = z >> 16;
32759cc4ca5SDavid du Colombier 				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
32859cc4ca5SDavid du Colombier 				carry = z2 >> 16;
32959cc4ca5SDavid du Colombier 				Storeinc(xc, z2, z);
33059cc4ca5SDavid du Colombier 			} while (x < xae);
33159cc4ca5SDavid du Colombier 			*xc = carry;
33259cc4ca5SDavid du Colombier 		}
33359cc4ca5SDavid du Colombier 		if (y = *xb >> 16) {
33459cc4ca5SDavid du Colombier 			x = xa;
33559cc4ca5SDavid du Colombier 			xc = xc0;
33659cc4ca5SDavid du Colombier 			carry = 0;
33759cc4ca5SDavid du Colombier 			z2 = *xc;
33859cc4ca5SDavid du Colombier 			do {
33959cc4ca5SDavid du Colombier 				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
34059cc4ca5SDavid du Colombier 				carry = z >> 16;
34159cc4ca5SDavid du Colombier 				Storeinc(xc, z, z2);
34259cc4ca5SDavid du Colombier 				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
34359cc4ca5SDavid du Colombier 				carry = z2 >> 16;
34459cc4ca5SDavid du Colombier 			} while (x < xae);
34559cc4ca5SDavid du Colombier 			*xc = z2;
34659cc4ca5SDavid du Colombier 		}
34759cc4ca5SDavid du Colombier 	}
34859cc4ca5SDavid du Colombier 	for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc)
34959cc4ca5SDavid du Colombier 		;
35059cc4ca5SDavid du Colombier 	c->wds = wc;
35159cc4ca5SDavid du Colombier 	return c;
35259cc4ca5SDavid du Colombier }
35359cc4ca5SDavid du Colombier 
35459cc4ca5SDavid du Colombier static Bigint *p5s;
35559cc4ca5SDavid du Colombier 
35659cc4ca5SDavid du Colombier static Bigint *
pow5mult(Bigint * b,int k)35759cc4ca5SDavid du Colombier pow5mult(Bigint *b, int k)
35859cc4ca5SDavid du Colombier {
35959cc4ca5SDavid du Colombier 	Bigint * b1, *p5, *p51;
36059cc4ca5SDavid du Colombier 	int	i;
36159cc4ca5SDavid du Colombier 	static int	p05[3] = {
36259cc4ca5SDavid du Colombier 		5, 25, 125 	};
36359cc4ca5SDavid du Colombier 
36459cc4ca5SDavid du Colombier 	if (i = k & 3)
36559cc4ca5SDavid du Colombier 		b = multadd(b, p05[i-1], 0);
36659cc4ca5SDavid du Colombier 
36759cc4ca5SDavid du Colombier 	if (!(k >>= 2))
36859cc4ca5SDavid du Colombier 		return b;
36959cc4ca5SDavid du Colombier 	if (!(p5 = p5s)) {
37059cc4ca5SDavid du Colombier 		/* first time */
37159cc4ca5SDavid du Colombier 		ACQUIRE_DTOA_LOCK(1);
37259cc4ca5SDavid du Colombier 		if (!(p5 = p5s)) {
37359cc4ca5SDavid du Colombier 			p5 = p5s = i2b(625);
37459cc4ca5SDavid du Colombier 			p5->next = 0;
37559cc4ca5SDavid du Colombier 		}
37659cc4ca5SDavid du Colombier 		FREE_DTOA_LOCK(1);
37759cc4ca5SDavid du Colombier 	}
37859cc4ca5SDavid du Colombier 	for (; ; ) {
37959cc4ca5SDavid du Colombier 		if (k & 1) {
38059cc4ca5SDavid du Colombier 			b1 = mult(b, p5);
38159cc4ca5SDavid du Colombier 			Bfree(b);
38259cc4ca5SDavid du Colombier 			b = b1;
38359cc4ca5SDavid du Colombier 		}
38459cc4ca5SDavid du Colombier 		if (!(k >>= 1))
38559cc4ca5SDavid du Colombier 			break;
38659cc4ca5SDavid du Colombier 		if (!(p51 = p5->next)) {
38759cc4ca5SDavid du Colombier 			ACQUIRE_DTOA_LOCK(1);
38859cc4ca5SDavid du Colombier 			if (!(p51 = p5->next)) {
38959cc4ca5SDavid du Colombier 				p51 = p5->next = mult(p5, p5);
39059cc4ca5SDavid du Colombier 				p51->next = 0;
39159cc4ca5SDavid du Colombier 			}
39259cc4ca5SDavid du Colombier 			FREE_DTOA_LOCK(1);
39359cc4ca5SDavid du Colombier 		}
39459cc4ca5SDavid du Colombier 		p5 = p51;
39559cc4ca5SDavid du Colombier 	}
39659cc4ca5SDavid du Colombier 	return b;
39759cc4ca5SDavid du Colombier }
39859cc4ca5SDavid du Colombier 
39959cc4ca5SDavid du Colombier static Bigint *
lshift(Bigint * b,int k)40059cc4ca5SDavid du Colombier lshift(Bigint *b, int k)
40159cc4ca5SDavid du Colombier {
40259cc4ca5SDavid du Colombier 	int	i, k1, n, n1;
40359cc4ca5SDavid du Colombier 	Bigint * b1;
40459cc4ca5SDavid du Colombier 	unsigned int * x, *x1, *xe, z;
40559cc4ca5SDavid du Colombier 
40659cc4ca5SDavid du Colombier 	n = k >> 5;
40759cc4ca5SDavid du Colombier 	k1 = b->k;
40859cc4ca5SDavid du Colombier 	n1 = n + b->wds + 1;
40959cc4ca5SDavid du Colombier 	for (i = b->maxwds; n1 > i; i <<= 1)
41059cc4ca5SDavid du Colombier 		k1++;
41159cc4ca5SDavid du Colombier 	b1 = Balloc(k1);
41259cc4ca5SDavid du Colombier 	x1 = b1->x;
41359cc4ca5SDavid du Colombier 	for (i = 0; i < n; i++)
41459cc4ca5SDavid du Colombier 		*x1++ = 0;
41559cc4ca5SDavid du Colombier 	x = b->x;
41659cc4ca5SDavid du Colombier 	xe = x + b->wds;
41759cc4ca5SDavid du Colombier 	if (k &= 0x1f) {
41859cc4ca5SDavid du Colombier 		k1 = 32 - k;
41959cc4ca5SDavid du Colombier 		z = 0;
42059cc4ca5SDavid du Colombier 		do {
42159cc4ca5SDavid du Colombier 			*x1++ = *x << k | z;
42259cc4ca5SDavid du Colombier 			z = *x++ >> k1;
42359cc4ca5SDavid du Colombier 		} while (x < xe);
42459cc4ca5SDavid du Colombier 		if (*x1 = z)
42559cc4ca5SDavid du Colombier 			++n1;
42659cc4ca5SDavid du Colombier 	} else
42759cc4ca5SDavid du Colombier 		do
42859cc4ca5SDavid du Colombier 			*x1++ = *x++;
42959cc4ca5SDavid du Colombier 		while (x < xe);
43059cc4ca5SDavid du Colombier 	b1->wds = n1 - 1;
43159cc4ca5SDavid du Colombier 	Bfree(b);
43259cc4ca5SDavid du Colombier 	return b1;
43359cc4ca5SDavid du Colombier }
43459cc4ca5SDavid du Colombier 
43559cc4ca5SDavid du Colombier static int
cmp(Bigint * a,Bigint * b)43659cc4ca5SDavid du Colombier cmp(Bigint *a, Bigint *b)
43759cc4ca5SDavid du Colombier {
43859cc4ca5SDavid du Colombier 	unsigned int * xa, *xa0, *xb, *xb0;
43959cc4ca5SDavid du Colombier 	int	i, j;
44059cc4ca5SDavid du Colombier 
44159cc4ca5SDavid du Colombier 	i = a->wds;
44259cc4ca5SDavid du Colombier 	j = b->wds;
44359cc4ca5SDavid du Colombier 	if (i -= j)
44459cc4ca5SDavid du Colombier 		return i;
44559cc4ca5SDavid du Colombier 	xa0 = a->x;
44659cc4ca5SDavid du Colombier 	xa = xa0 + j;
44759cc4ca5SDavid du Colombier 	xb0 = b->x;
44859cc4ca5SDavid du Colombier 	xb = xb0 + j;
44959cc4ca5SDavid du Colombier 	for (; ; ) {
45059cc4ca5SDavid du Colombier 		if (*--xa != *--xb)
45159cc4ca5SDavid du Colombier 			return * xa < *xb ? -1 : 1;
45259cc4ca5SDavid du Colombier 		if (xa <= xa0)
45359cc4ca5SDavid du Colombier 			break;
45459cc4ca5SDavid du Colombier 	}
45559cc4ca5SDavid du Colombier 	return 0;
45659cc4ca5SDavid du Colombier }
45759cc4ca5SDavid du Colombier 
45859cc4ca5SDavid du Colombier static Bigint *
diff(Bigint * a,Bigint * b)45959cc4ca5SDavid du Colombier diff(Bigint *a, Bigint *b)
46059cc4ca5SDavid du Colombier {
46159cc4ca5SDavid du Colombier 	Bigint * c;
46259cc4ca5SDavid du Colombier 	int	i, wa, wb;
46359cc4ca5SDavid du Colombier 	unsigned int * xa, *xae, *xb, *xbe, *xc;
46459cc4ca5SDavid du Colombier 	unsigned int borrow, y;
46559cc4ca5SDavid du Colombier 	unsigned int z;
46659cc4ca5SDavid du Colombier 
46759cc4ca5SDavid du Colombier 	i = cmp(a, b);
46859cc4ca5SDavid du Colombier 	if (!i) {
46959cc4ca5SDavid du Colombier 		c = Balloc(0);
47059cc4ca5SDavid du Colombier 		c->wds = 1;
47159cc4ca5SDavid du Colombier 		c->x[0] = 0;
47259cc4ca5SDavid du Colombier 		return c;
47359cc4ca5SDavid du Colombier 	}
47459cc4ca5SDavid du Colombier 	if (i < 0) {
47559cc4ca5SDavid du Colombier 		c = a;
47659cc4ca5SDavid du Colombier 		a = b;
47759cc4ca5SDavid du Colombier 		b = c;
47859cc4ca5SDavid du Colombier 		i = 1;
47959cc4ca5SDavid du Colombier 	} else
48059cc4ca5SDavid du Colombier 		i = 0;
48159cc4ca5SDavid du Colombier 	c = Balloc(a->k);
48259cc4ca5SDavid du Colombier 	c->sign = i;
48359cc4ca5SDavid du Colombier 	wa = a->wds;
48459cc4ca5SDavid du Colombier 	xa = a->x;
48559cc4ca5SDavid du Colombier 	xae = xa + wa;
48659cc4ca5SDavid du Colombier 	wb = b->wds;
48759cc4ca5SDavid du Colombier 	xb = b->x;
48859cc4ca5SDavid du Colombier 	xbe = xb + wb;
48959cc4ca5SDavid du Colombier 	xc = c->x;
49059cc4ca5SDavid du Colombier 	borrow = 0;
49159cc4ca5SDavid du Colombier 	do {
49259cc4ca5SDavid du Colombier 		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
49359cc4ca5SDavid du Colombier 		borrow = (y & 0x10000) >> 16;
49459cc4ca5SDavid du Colombier 		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
49559cc4ca5SDavid du Colombier 		borrow = (z & 0x10000) >> 16;
49659cc4ca5SDavid du Colombier 		Storeinc(xc, z, y);
49759cc4ca5SDavid du Colombier 	} while (xb < xbe);
49859cc4ca5SDavid du Colombier 	while (xa < xae) {
49959cc4ca5SDavid du Colombier 		y = (*xa & 0xffff) - borrow;
50059cc4ca5SDavid du Colombier 		borrow = (y & 0x10000) >> 16;
50159cc4ca5SDavid du Colombier 		z = (*xa++ >> 16) - borrow;
50259cc4ca5SDavid du Colombier 		borrow = (z & 0x10000) >> 16;
50359cc4ca5SDavid du Colombier 		Storeinc(xc, z, y);
50459cc4ca5SDavid du Colombier 	}
50559cc4ca5SDavid du Colombier 	while (!*--xc)
50659cc4ca5SDavid du Colombier 		wa--;
50759cc4ca5SDavid du Colombier 	c->wds = wa;
50859cc4ca5SDavid du Colombier 	return c;
50959cc4ca5SDavid du Colombier }
51059cc4ca5SDavid du Colombier 
51159cc4ca5SDavid du Colombier static double
ulp(double x)51259cc4ca5SDavid du Colombier ulp(double x)
51359cc4ca5SDavid du Colombier {
514*eea45bbcSDavid du Colombier 	ulong L;
515*eea45bbcSDavid du Colombier 	Ulongs uls;
51659cc4ca5SDavid du Colombier 
517*eea45bbcSDavid du Colombier 	uls = double2ulongs(x);
518*eea45bbcSDavid du Colombier 	L = (uls.hi & Exp_mask) - (P - 1) * Exp_msk1;
5198c242bd4SDavid du Colombier 	return ulongs2double((Ulongs){L, 0});
52059cc4ca5SDavid du Colombier }
52159cc4ca5SDavid du Colombier 
52259cc4ca5SDavid du Colombier static double
b2d(Bigint * a,int * e)52359cc4ca5SDavid du Colombier b2d(Bigint *a, int *e)
52459cc4ca5SDavid du Colombier {
5258c242bd4SDavid du Colombier 	unsigned *xa, *xa0, w, y, z;
52659cc4ca5SDavid du Colombier 	int	k;
5278c242bd4SDavid du Colombier 	ulong d0, d1;
52859cc4ca5SDavid du Colombier 
52959cc4ca5SDavid du Colombier 	xa0 = a->x;
53059cc4ca5SDavid du Colombier 	xa = xa0 + a->wds;
53159cc4ca5SDavid du Colombier 	y = *--xa;
53259cc4ca5SDavid du Colombier 	k = hi0bits(y);
53359cc4ca5SDavid du Colombier 	*e = 32 - k;
53459cc4ca5SDavid du Colombier 	if (k < Ebits) {
53559cc4ca5SDavid du Colombier 		w = xa > xa0 ? *--xa : 0;
53659cc4ca5SDavid du Colombier 		d1 = y << (32 - Ebits) + k | w >> Ebits - k;
5378c242bd4SDavid du Colombier 		return ulongs2double((Ulongs){Exp_1 | y >> Ebits - k, d1});
53859cc4ca5SDavid du Colombier 	}
53959cc4ca5SDavid du Colombier 	z = xa > xa0 ? *--xa : 0;
54059cc4ca5SDavid du Colombier 	if (k -= Ebits) {
54159cc4ca5SDavid du Colombier 		d0 = Exp_1 | y << k | z >> 32 - k;
54259cc4ca5SDavid du Colombier 		y = xa > xa0 ? *--xa : 0;
54359cc4ca5SDavid du Colombier 		d1 = z << k | y >> 32 - k;
54459cc4ca5SDavid du Colombier 	} else {
54559cc4ca5SDavid du Colombier 		d0 = Exp_1 | y;
54659cc4ca5SDavid du Colombier 		d1 = z;
54759cc4ca5SDavid du Colombier 	}
5488c242bd4SDavid du Colombier 	return ulongs2double((Ulongs){d0, d1});
54959cc4ca5SDavid du Colombier }
55059cc4ca5SDavid du Colombier 
55159cc4ca5SDavid du Colombier static Bigint *
d2b(double d,int * e,int * bits)55259cc4ca5SDavid du Colombier d2b(double d, int *e, int *bits)
55359cc4ca5SDavid du Colombier {
55459cc4ca5SDavid du Colombier 	Bigint * b;
55559cc4ca5SDavid du Colombier 	int	de, i, k;
5568c242bd4SDavid du Colombier 	unsigned *x, y, z;
5578c242bd4SDavid du Colombier 	Ulongs uls;
55859cc4ca5SDavid du Colombier 
55959cc4ca5SDavid du Colombier 	b = Balloc(1);
56059cc4ca5SDavid du Colombier 	x = b->x;
56159cc4ca5SDavid du Colombier 
5628c242bd4SDavid du Colombier 	uls = double2ulongs(d);
5638c242bd4SDavid du Colombier 	z = uls.hi & Frac_mask;
5648c242bd4SDavid du Colombier 	uls.hi &= 0x7fffffff;		/* clear sign bit, which we ignore */
5658c242bd4SDavid du Colombier 	de = (int)(uls.hi >> Exp_shift);
56659cc4ca5SDavid du Colombier 	z |= Exp_msk11;
5678c242bd4SDavid du Colombier 	if (y = uls.lo) {		/* assignment = */
568*eea45bbcSDavid du Colombier 		if (k = lo0bits(&y)) {	/* assignment = */
56959cc4ca5SDavid du Colombier 			x[0] = y | z << 32 - k;
57059cc4ca5SDavid du Colombier 			z >>= k;
57159cc4ca5SDavid du Colombier 		} else
57259cc4ca5SDavid du Colombier 			x[0] = y;
57359cc4ca5SDavid du Colombier 		i = b->wds = (x[1] = z) ? 2 : 1;
57459cc4ca5SDavid du Colombier 	} else {
57559cc4ca5SDavid du Colombier 		k = lo0bits(&z);
57659cc4ca5SDavid du Colombier 		x[0] = z;
57759cc4ca5SDavid du Colombier 		i = b->wds = 1;
57859cc4ca5SDavid du Colombier 		k += 32;
57959cc4ca5SDavid du Colombier 	}
5808c242bd4SDavid du Colombier 	USED(i);
58159cc4ca5SDavid du Colombier 	*e = de - Bias - (P - 1) + k;
58259cc4ca5SDavid du Colombier 	*bits = P - k;
58359cc4ca5SDavid du Colombier 	return b;
58459cc4ca5SDavid du Colombier }
58559cc4ca5SDavid du Colombier 
58659cc4ca5SDavid du Colombier static double
ratio(Bigint * a,Bigint * b)58759cc4ca5SDavid du Colombier ratio(Bigint *a, Bigint *b)
58859cc4ca5SDavid du Colombier {
58959cc4ca5SDavid du Colombier 	double	da, db;
59059cc4ca5SDavid du Colombier 	int	k, ka, kb;
5918c242bd4SDavid du Colombier 	Ulongs uls;
59259cc4ca5SDavid du Colombier 
59359cc4ca5SDavid du Colombier 	da = b2d(a, &ka);
59459cc4ca5SDavid du Colombier 	db = b2d(b, &kb);
59559cc4ca5SDavid du Colombier 	k = ka - kb + 32 * (a->wds - b->wds);
5968c242bd4SDavid du Colombier 	if (k > 0) {
5978c242bd4SDavid du Colombier 		uls = double2ulongs(da);
5988c242bd4SDavid du Colombier 		uls.hi += k * Exp_msk1;
5998c242bd4SDavid du Colombier 		da = ulongs2double(uls);
6008c242bd4SDavid du Colombier 	} else {
60159cc4ca5SDavid du Colombier 		k = -k;
6028c242bd4SDavid du Colombier 		uls = double2ulongs(db);
6038c242bd4SDavid du Colombier 		uls.hi += k * Exp_msk1;
6048c242bd4SDavid du Colombier 		db = ulongs2double(uls);
60559cc4ca5SDavid du Colombier 	}
60659cc4ca5SDavid du Colombier 	return da / db;
60759cc4ca5SDavid du Colombier }
60859cc4ca5SDavid du Colombier 
60959cc4ca5SDavid du Colombier static const double
61059cc4ca5SDavid du Colombier tens[] = {
61159cc4ca5SDavid du Colombier 	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
61259cc4ca5SDavid du Colombier 	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
61359cc4ca5SDavid du Colombier 	1e20, 1e21, 1e22
61459cc4ca5SDavid du Colombier };
61559cc4ca5SDavid du Colombier 
61659cc4ca5SDavid du Colombier static const double
61759cc4ca5SDavid du Colombier bigtens[] = {
61859cc4ca5SDavid du Colombier 	1e16, 1e32, 1e64, 1e128, 1e256 };
61959cc4ca5SDavid du Colombier 
62059cc4ca5SDavid du Colombier static const double tinytens[] = {
62159cc4ca5SDavid du Colombier 	1e-16, 1e-32, 1e-64, 1e-128,
62259cc4ca5SDavid du Colombier 	9007199254740992.e-256
62359cc4ca5SDavid du Colombier };
62459cc4ca5SDavid du Colombier 
62559cc4ca5SDavid du Colombier /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
62659cc4ca5SDavid du Colombier /* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
62759cc4ca5SDavid du Colombier #define Scale_Bit 0x10
62859cc4ca5SDavid du Colombier #define n_bigtens 5
62959cc4ca5SDavid du Colombier 
63059cc4ca5SDavid du Colombier #define NAN_WORD0 0x7ff80000
63159cc4ca5SDavid du Colombier 
63259cc4ca5SDavid du Colombier #define NAN_WORD1 0
63359cc4ca5SDavid du Colombier 
63459cc4ca5SDavid du Colombier static int
match(const char ** sp,char * t)63559cc4ca5SDavid du Colombier match(const char **sp, char *t)
63659cc4ca5SDavid du Colombier {
63759cc4ca5SDavid du Colombier 	int	c, d;
63859cc4ca5SDavid du Colombier 	const char * s = *sp;
63959cc4ca5SDavid du Colombier 
64059cc4ca5SDavid du Colombier 	while (d = *t++) {
64159cc4ca5SDavid du Colombier 		if ((c = *++s) >= 'A' && c <= 'Z')
64259cc4ca5SDavid du Colombier 			c += 'a' - 'A';
64359cc4ca5SDavid du Colombier 		if (c != d)
64459cc4ca5SDavid du Colombier 			return 0;
64559cc4ca5SDavid du Colombier 	}
64659cc4ca5SDavid du Colombier 	*sp = s + 1;
64759cc4ca5SDavid du Colombier 	return 1;
64859cc4ca5SDavid du Colombier }
64959cc4ca5SDavid du Colombier 
65059cc4ca5SDavid du Colombier static void
gethex(double * rvp,const char ** sp)65159cc4ca5SDavid du Colombier gethex(double *rvp, const char **sp)
65259cc4ca5SDavid du Colombier {
65359cc4ca5SDavid du Colombier 	unsigned int c, x[2];
65459cc4ca5SDavid du Colombier 	const char * s;
65559cc4ca5SDavid du Colombier 	int	havedig, udx0, xshift;
65659cc4ca5SDavid du Colombier 
65759cc4ca5SDavid du Colombier 	x[0] = x[1] = 0;
65859cc4ca5SDavid du Colombier 	havedig = xshift = 0;
65959cc4ca5SDavid du Colombier 	udx0 = 1;
66059cc4ca5SDavid du Colombier 	s = *sp;
66159cc4ca5SDavid du Colombier 	while (c = *(const unsigned char * )++s) {
66259cc4ca5SDavid du Colombier 		if (c >= '0' && c <= '9')
66359cc4ca5SDavid du Colombier 			c -= '0';
66459cc4ca5SDavid du Colombier 		else if (c >= 'a' && c <= 'f')
66559cc4ca5SDavid du Colombier 			c += 10 - 'a';
66659cc4ca5SDavid du Colombier 		else if (c >= 'A' && c <= 'F')
66759cc4ca5SDavid du Colombier 			c += 10 - 'A';
66859cc4ca5SDavid du Colombier 		else if (c <= ' ') {
66959cc4ca5SDavid du Colombier 			if (udx0 && havedig) {
67059cc4ca5SDavid du Colombier 				udx0 = 0;
67159cc4ca5SDavid du Colombier 				xshift = 1;
67259cc4ca5SDavid du Colombier 			}
67359cc4ca5SDavid du Colombier 			continue;
67459cc4ca5SDavid du Colombier 		} else if (/*(*/ c == ')') {
67559cc4ca5SDavid du Colombier 			*sp = s + 1;
67659cc4ca5SDavid du Colombier 			break;
67759cc4ca5SDavid du Colombier 		} else
67859cc4ca5SDavid du Colombier 			return;	/* invalid form: don't change *sp */
67959cc4ca5SDavid du Colombier 		havedig = 1;
68059cc4ca5SDavid du Colombier 		if (xshift) {
68159cc4ca5SDavid du Colombier 			xshift = 0;
68259cc4ca5SDavid du Colombier 			x[0] = x[1];
68359cc4ca5SDavid du Colombier 			x[1] = 0;
68459cc4ca5SDavid du Colombier 		}
68559cc4ca5SDavid du Colombier 		if (udx0)
68659cc4ca5SDavid du Colombier 			x[0] = (x[0] << 4) | (x[1] >> 28);
68759cc4ca5SDavid du Colombier 		x[1] = (x[1] << 4) | c;
68859cc4ca5SDavid du Colombier 	}
6898c242bd4SDavid du Colombier 	if ((x[0] &= 0xfffff) || x[1])
6908c242bd4SDavid du Colombier 		*rvp = ulongs2double((Ulongs){Exp_mask | x[0], x[1]});
69159cc4ca5SDavid du Colombier }
69259cc4ca5SDavid du Colombier 
69359cc4ca5SDavid du Colombier static int
quorem(Bigint * b,Bigint * S)69459cc4ca5SDavid du Colombier quorem(Bigint *b, Bigint *S)
69559cc4ca5SDavid du Colombier {
69659cc4ca5SDavid du Colombier 	int	n;
69759cc4ca5SDavid du Colombier 	unsigned int * bx, *bxe, q, *sx, *sxe;
69859cc4ca5SDavid du Colombier 	unsigned int borrow, carry, y, ys;
69959cc4ca5SDavid du Colombier 	unsigned int si, z, zs;
70059cc4ca5SDavid du Colombier 
70159cc4ca5SDavid du Colombier 	n = S->wds;
70259cc4ca5SDavid du Colombier 	if (b->wds < n)
70359cc4ca5SDavid du Colombier 		return 0;
70459cc4ca5SDavid du Colombier 	sx = S->x;
70559cc4ca5SDavid du Colombier 	sxe = sx + --n;
70659cc4ca5SDavid du Colombier 	bx = b->x;
70759cc4ca5SDavid du Colombier 	bxe = bx + n;
70859cc4ca5SDavid du Colombier 	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
70959cc4ca5SDavid du Colombier 	if (q) {
71059cc4ca5SDavid du Colombier 		borrow = 0;
71159cc4ca5SDavid du Colombier 		carry = 0;
71259cc4ca5SDavid du Colombier 		do {
71359cc4ca5SDavid du Colombier 			si = *sx++;
71459cc4ca5SDavid du Colombier 			ys = (si & 0xffff) * q + carry;
71559cc4ca5SDavid du Colombier 			zs = (si >> 16) * q + (ys >> 16);
71659cc4ca5SDavid du Colombier 			carry = zs >> 16;
71759cc4ca5SDavid du Colombier 			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
71859cc4ca5SDavid du Colombier 			borrow = (y & 0x10000) >> 16;
71959cc4ca5SDavid du Colombier 			z = (*bx >> 16) - (zs & 0xffff) - borrow;
72059cc4ca5SDavid du Colombier 			borrow = (z & 0x10000) >> 16;
72159cc4ca5SDavid du Colombier 			Storeinc(bx, z, y);
72259cc4ca5SDavid du Colombier 		} while (sx <= sxe);
72359cc4ca5SDavid du Colombier 		if (!*bxe) {
72459cc4ca5SDavid du Colombier 			bx = b->x;
72559cc4ca5SDavid du Colombier 			while (--bxe > bx && !*bxe)
72659cc4ca5SDavid du Colombier 				--n;
72759cc4ca5SDavid du Colombier 			b->wds = n;
72859cc4ca5SDavid du Colombier 		}
72959cc4ca5SDavid du Colombier 	}
73059cc4ca5SDavid du Colombier 	if (cmp(b, S) >= 0) {
73159cc4ca5SDavid du Colombier 		q++;
73259cc4ca5SDavid du Colombier 		borrow = 0;
73359cc4ca5SDavid du Colombier 		carry = 0;
73459cc4ca5SDavid du Colombier 		bx = b->x;
73559cc4ca5SDavid du Colombier 		sx = S->x;
73659cc4ca5SDavid du Colombier 		do {
73759cc4ca5SDavid du Colombier 			si = *sx++;
73859cc4ca5SDavid du Colombier 			ys = (si & 0xffff) + carry;
73959cc4ca5SDavid du Colombier 			zs = (si >> 16) + (ys >> 16);
74059cc4ca5SDavid du Colombier 			carry = zs >> 16;
74159cc4ca5SDavid du Colombier 			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
74259cc4ca5SDavid du Colombier 			borrow = (y & 0x10000) >> 16;
74359cc4ca5SDavid du Colombier 			z = (*bx >> 16) - (zs & 0xffff) - borrow;
74459cc4ca5SDavid du Colombier 			borrow = (z & 0x10000) >> 16;
74559cc4ca5SDavid du Colombier 			Storeinc(bx, z, y);
74659cc4ca5SDavid du Colombier 		} while (sx <= sxe);
74759cc4ca5SDavid du Colombier 		bx = b->x;
74859cc4ca5SDavid du Colombier 		bxe = bx + n;
74959cc4ca5SDavid du Colombier 		if (!*bxe) {
75059cc4ca5SDavid du Colombier 			while (--bxe > bx && !*bxe)
75159cc4ca5SDavid du Colombier 				--n;
75259cc4ca5SDavid du Colombier 			b->wds = n;
75359cc4ca5SDavid du Colombier 		}
75459cc4ca5SDavid du Colombier 	}
75559cc4ca5SDavid du Colombier 	return q;
75659cc4ca5SDavid du Colombier }
75759cc4ca5SDavid du Colombier 
75859cc4ca5SDavid du Colombier static char	*
rv_alloc(int i)75959cc4ca5SDavid du Colombier rv_alloc(int i)
76059cc4ca5SDavid du Colombier {
76159cc4ca5SDavid du Colombier 	int	j, k, *r;
76259cc4ca5SDavid du Colombier 
76359cc4ca5SDavid du Colombier 	j = sizeof(unsigned int);
76459cc4ca5SDavid du Colombier 	for (k = 0;
76559cc4ca5SDavid du Colombier 	    sizeof(Bigint) - sizeof(unsigned int) - sizeof(int) + j <= i;
76659cc4ca5SDavid du Colombier 	    j <<= 1)
76759cc4ca5SDavid du Colombier 		k++;
76859cc4ca5SDavid du Colombier 	r = (int * )Balloc(k);
76959cc4ca5SDavid du Colombier 	*r = k;
77059cc4ca5SDavid du Colombier 	return
77159cc4ca5SDavid du Colombier 	    (char *)(r + 1);
77259cc4ca5SDavid du Colombier }
77359cc4ca5SDavid du Colombier 
77459cc4ca5SDavid du Colombier static char	*
nrv_alloc(char * s,char ** rve,int n)77559cc4ca5SDavid du Colombier nrv_alloc(char *s, char **rve, int n)
77659cc4ca5SDavid du Colombier {
77759cc4ca5SDavid du Colombier 	char	*rv, *t;
77859cc4ca5SDavid du Colombier 
77959cc4ca5SDavid du Colombier 	t = rv = rv_alloc(n);
78059cc4ca5SDavid du Colombier 	while (*t = *s++)
78159cc4ca5SDavid du Colombier 		t++;
78259cc4ca5SDavid du Colombier 	if (rve)
78359cc4ca5SDavid du Colombier 		*rve = t;
78459cc4ca5SDavid du Colombier 	return rv;
78559cc4ca5SDavid du Colombier }
78659cc4ca5SDavid du Colombier 
78759cc4ca5SDavid du Colombier /* freedtoa(s) must be used to free values s returned by dtoa
78859cc4ca5SDavid du Colombier  * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
78959cc4ca5SDavid du Colombier  * but for consistency with earlier versions of dtoa, it is optional
79059cc4ca5SDavid du Colombier  * when MULTIPLE_THREADS is not defined.
79159cc4ca5SDavid du Colombier  */
79259cc4ca5SDavid du Colombier 
79359cc4ca5SDavid du Colombier void
freedtoa(char * s)79459cc4ca5SDavid du Colombier freedtoa(char *s)
79559cc4ca5SDavid du Colombier {
79659cc4ca5SDavid du Colombier 	Bigint * b = (Bigint * )((int *)s - 1);
79759cc4ca5SDavid du Colombier 	b->maxwds = 1 << (b->k = *(int * )b);
79859cc4ca5SDavid du Colombier 	Bfree(b);
79959cc4ca5SDavid du Colombier }
80059cc4ca5SDavid du Colombier 
80159cc4ca5SDavid du Colombier /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
80259cc4ca5SDavid du Colombier  *
80359cc4ca5SDavid du Colombier  * Inspired by "How to Print Floating-Point Numbers Accurately" by
80459cc4ca5SDavid du Colombier  * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
80559cc4ca5SDavid du Colombier  *
80659cc4ca5SDavid du Colombier  * Modifications:
80759cc4ca5SDavid du Colombier  *	1. Rather than iterating, we use a simple numeric overestimate
80859cc4ca5SDavid du Colombier  *	   to determine k = floor(log10(d)).  We scale relevant
80959cc4ca5SDavid du Colombier  *	   quantities using O(log2(k)) rather than O(k) multiplications.
81059cc4ca5SDavid du Colombier  *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
81159cc4ca5SDavid du Colombier  *	   try to generate digits strictly left to right.  Instead, we
81259cc4ca5SDavid du Colombier  *	   compute with fewer bits and propagate the carry if necessary
81359cc4ca5SDavid du Colombier  *	   when rounding the final digit up.  This is often faster.
81459cc4ca5SDavid du Colombier  *	3. Under the assumption that input will be rounded nearest,
81559cc4ca5SDavid du Colombier  *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
81659cc4ca5SDavid du Colombier  *	   That is, we allow equality in stopping tests when the
81759cc4ca5SDavid du Colombier  *	   round-nearest rule will give the same floating-point value
81859cc4ca5SDavid du Colombier  *	   as would satisfaction of the stopping test with strict
81959cc4ca5SDavid du Colombier  *	   inequality.
82059cc4ca5SDavid du Colombier  *	4. We remove common factors of powers of 2 from relevant
82159cc4ca5SDavid du Colombier  *	   quantities.
82259cc4ca5SDavid du Colombier  *	5. When converting floating-point integers less than 1e16,
82359cc4ca5SDavid du Colombier  *	   we use floating-point arithmetic rather than resorting
82459cc4ca5SDavid du Colombier  *	   to multiple-precision integers.
82559cc4ca5SDavid du Colombier  *	6. When asked to produce fewer than 15 digits, we first try
82659cc4ca5SDavid du Colombier  *	   to get by with floating-point arithmetic; we resort to
82759cc4ca5SDavid du Colombier  *	   multiple-precision integer arithmetic only if we cannot
82859cc4ca5SDavid du Colombier  *	   guarantee that the floating-point calculation has given
82959cc4ca5SDavid du Colombier  *	   the correctly rounded result.  For k requested digits and
83059cc4ca5SDavid du Colombier  *	   "uniformly" distributed input, the probability is
83159cc4ca5SDavid du Colombier  *	   something like 10^(k-15) that we must resort to the int
83259cc4ca5SDavid du Colombier  *	   calculation.
83359cc4ca5SDavid du Colombier  */
83459cc4ca5SDavid du Colombier 
83559cc4ca5SDavid du Colombier char	*
dtoa(double d,int mode,int ndigits,int * decpt,int * sign,char ** rve)83659cc4ca5SDavid du Colombier dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
83759cc4ca5SDavid du Colombier {
83859cc4ca5SDavid du Colombier 	/*	Arguments ndigits, decpt, sign are similar to those
83959cc4ca5SDavid du Colombier 	of ecvt and fcvt; trailing zeros are suppressed from
84059cc4ca5SDavid du Colombier 	the returned string.  If not null, *rve is set to point
84159cc4ca5SDavid du Colombier 	to the end of the return value.  If d is +-Infinity or NaN,
84259cc4ca5SDavid du Colombier 	then *decpt is set to 9999.
84359cc4ca5SDavid du Colombier 
84459cc4ca5SDavid du Colombier 	mode:
84559cc4ca5SDavid du Colombier 		0 ==> shortest string that yields d when read in
84659cc4ca5SDavid du Colombier 			and rounded to nearest.
84759cc4ca5SDavid du Colombier 		1 ==> like 0, but with Steele & White stopping rule;
84859cc4ca5SDavid du Colombier 			e.g. with IEEE P754 arithmetic , mode 0 gives
84959cc4ca5SDavid du Colombier 			1e23 whereas mode 1 gives 9.999999999999999e22.
85059cc4ca5SDavid du Colombier 		2 ==> max(1,ndigits) significant digits.  This gives a
85159cc4ca5SDavid du Colombier 			return value similar to that of ecvt, except
85259cc4ca5SDavid du Colombier 			that trailing zeros are suppressed.
85359cc4ca5SDavid du Colombier 		3 ==> through ndigits past the decimal point.  This
85459cc4ca5SDavid du Colombier 			gives a return value similar to that from fcvt,
85559cc4ca5SDavid du Colombier 			except that trailing zeros are suppressed, and
85659cc4ca5SDavid du Colombier 			ndigits can be negative.
85759cc4ca5SDavid du Colombier 		4-9 should give the same return values as 2-3, i.e.,
85859cc4ca5SDavid du Colombier 			4 <= mode <= 9 ==> same return as mode
85959cc4ca5SDavid du Colombier 			2 + (mode & 1).  These modes are mainly for
86059cc4ca5SDavid du Colombier 			debugging; often they run slower but sometimes
86159cc4ca5SDavid du Colombier 			faster than modes 2-3.
86259cc4ca5SDavid du Colombier 		4,5,8,9 ==> left-to-right digit generation.
86359cc4ca5SDavid du Colombier 		6-9 ==> don't try fast floating-point estimate
86459cc4ca5SDavid du Colombier 			(if applicable).
86559cc4ca5SDavid du Colombier 
86659cc4ca5SDavid du Colombier 		Values of mode other than 0-9 are treated as mode 0.
86759cc4ca5SDavid du Colombier 
86859cc4ca5SDavid du Colombier 		Sufficient space is allocated to the return value
86959cc4ca5SDavid du Colombier 		to hold the suppressed trailing zeros.
87059cc4ca5SDavid du Colombier 	*/
87159cc4ca5SDavid du Colombier 
87259cc4ca5SDavid du Colombier 	int	bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
8738c242bd4SDavid du Colombier 		j, j1, k, k0, k_check, L, leftright, m2, m5, s2, s5,
87459cc4ca5SDavid du Colombier 		spec_case, try_quick;
87559cc4ca5SDavid du Colombier 	Bigint * b, *b1, *delta, *mlo=nil, *mhi, *S;
87659cc4ca5SDavid du Colombier 	double	d2, ds, eps;
87759cc4ca5SDavid du Colombier 	char	*s, *s0;
8788c242bd4SDavid du Colombier 	Ulongs ulsd, ulsd2;
87959cc4ca5SDavid du Colombier 
8808c242bd4SDavid du Colombier 	ulsd = double2ulongs(d);
8818c242bd4SDavid du Colombier 	if (ulsd.hi & Sign_bit) {
88259cc4ca5SDavid du Colombier 		/* set sign for everything, including 0's and NaNs */
88359cc4ca5SDavid du Colombier 		*sign = 1;
8848c242bd4SDavid du Colombier 		ulsd.hi &= ~Sign_bit;	/* clear sign bit */
88559cc4ca5SDavid du Colombier 	} else
88659cc4ca5SDavid du Colombier 		*sign = 0;
88759cc4ca5SDavid du Colombier 
8888c242bd4SDavid du Colombier 	if ((ulsd.hi & Exp_mask) == Exp_mask) {
88959cc4ca5SDavid du Colombier 		/* Infinity or NaN */
89059cc4ca5SDavid du Colombier 		*decpt = 9999;
8918c242bd4SDavid du Colombier 		if (!ulsd.lo && !(ulsd.hi & 0xfffff))
89259cc4ca5SDavid du Colombier 			return nrv_alloc("Infinity", rve, 8);
89359cc4ca5SDavid du Colombier 		return nrv_alloc("NaN", rve, 3);
89459cc4ca5SDavid du Colombier 	}
8958c242bd4SDavid du Colombier 	d = ulongs2double(ulsd);
8968c242bd4SDavid du Colombier 
89759cc4ca5SDavid du Colombier 	if (!d) {
89859cc4ca5SDavid du Colombier 		*decpt = 1;
89959cc4ca5SDavid du Colombier 		return nrv_alloc("0", rve, 1);
90059cc4ca5SDavid du Colombier 	}
90159cc4ca5SDavid du Colombier 
90259cc4ca5SDavid du Colombier 	b = d2b(d, &be, &bbits);
9038c242bd4SDavid du Colombier 	i = (int)(ulsd.hi >> Exp_shift1 & (Exp_mask >> Exp_shift1));
9048c242bd4SDavid du Colombier 
9058c242bd4SDavid du Colombier 	ulsd2 = ulsd;
9068c242bd4SDavid du Colombier 	ulsd2.hi &= Frac_mask1;
907*eea45bbcSDavid du Colombier 	ulsd2.hi |= Exp_11;
9088c242bd4SDavid du Colombier 	d2 = ulongs2double(ulsd2);
90959cc4ca5SDavid du Colombier 
91059cc4ca5SDavid du Colombier 	/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
91159cc4ca5SDavid du Colombier 		 * log10(x)	 =  log(x) / log(10)
91259cc4ca5SDavid du Colombier 		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
91359cc4ca5SDavid du Colombier 		 * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
91459cc4ca5SDavid du Colombier 		 *
91559cc4ca5SDavid du Colombier 		 * This suggests computing an approximation k to log10(d) by
91659cc4ca5SDavid du Colombier 		 *
91759cc4ca5SDavid du Colombier 		 * k = (i - Bias)*0.301029995663981
91859cc4ca5SDavid du Colombier 		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
91959cc4ca5SDavid du Colombier 		 *
92059cc4ca5SDavid du Colombier 		 * We want k to be too large rather than too small.
92159cc4ca5SDavid du Colombier 		 * The error in the first-order Taylor series approximation
92259cc4ca5SDavid du Colombier 		 * is in our favor, so we just round up the constant enough
92359cc4ca5SDavid du Colombier 		 * to compensate for any error in the multiplication of
92459cc4ca5SDavid du Colombier 		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
92559cc4ca5SDavid du Colombier 		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
92659cc4ca5SDavid du Colombier 		 * adding 1e-13 to the constant term more than suffices.
92759cc4ca5SDavid du Colombier 		 * Hence we adjust the constant term to 0.1760912590558.
92859cc4ca5SDavid du Colombier 		 * (We could get a more accurate k by invoking log10,
92959cc4ca5SDavid du Colombier 		 *  but this is probably not worthwhile.)
93059cc4ca5SDavid du Colombier 		 */
93159cc4ca5SDavid du Colombier 
93259cc4ca5SDavid du Colombier 	i -= Bias;
93359cc4ca5SDavid du Colombier 	ds = (d2 - 1.5) * 0.289529654602168 + 0.1760912590558 + i * 0.301029995663981;
93459cc4ca5SDavid du Colombier 	k = (int)ds;
93559cc4ca5SDavid du Colombier 	if (ds < 0. && ds != k)
93659cc4ca5SDavid du Colombier 		k--;	/* want k = floor(ds) */
93759cc4ca5SDavid du Colombier 	k_check = 1;
93859cc4ca5SDavid du Colombier 	if (k >= 0 && k <= Ten_pmax) {
93959cc4ca5SDavid du Colombier 		if (d < tens[k])
94059cc4ca5SDavid du Colombier 			k--;
94159cc4ca5SDavid du Colombier 		k_check = 0;
94259cc4ca5SDavid du Colombier 	}
94359cc4ca5SDavid du Colombier 	j = bbits - i - 1;
94459cc4ca5SDavid du Colombier 	if (j >= 0) {
94559cc4ca5SDavid du Colombier 		b2 = 0;
94659cc4ca5SDavid du Colombier 		s2 = j;
94759cc4ca5SDavid du Colombier 	} else {
94859cc4ca5SDavid du Colombier 		b2 = -j;
94959cc4ca5SDavid du Colombier 		s2 = 0;
95059cc4ca5SDavid du Colombier 	}
95159cc4ca5SDavid du Colombier 	if (k >= 0) {
95259cc4ca5SDavid du Colombier 		b5 = 0;
95359cc4ca5SDavid du Colombier 		s5 = k;
95459cc4ca5SDavid du Colombier 		s2 += k;
95559cc4ca5SDavid du Colombier 	} else {
95659cc4ca5SDavid du Colombier 		b2 -= k;
95759cc4ca5SDavid du Colombier 		b5 = -k;
95859cc4ca5SDavid du Colombier 		s5 = 0;
95959cc4ca5SDavid du Colombier 	}
96059cc4ca5SDavid du Colombier 	if (mode < 0 || mode > 9)
96159cc4ca5SDavid du Colombier 		mode = 0;
96259cc4ca5SDavid du Colombier 	try_quick = 1;
96359cc4ca5SDavid du Colombier 	if (mode > 5) {
96459cc4ca5SDavid du Colombier 		mode -= 4;
96559cc4ca5SDavid du Colombier 		try_quick = 0;
96659cc4ca5SDavid du Colombier 	}
96759cc4ca5SDavid du Colombier 	leftright = 1;
96859cc4ca5SDavid du Colombier 	switch (mode) {
96959cc4ca5SDavid du Colombier 	case 0:
97059cc4ca5SDavid du Colombier 	case 1:
9718c242bd4SDavid du Colombier 	default:
97259cc4ca5SDavid du Colombier 		ilim = ilim1 = -1;
97359cc4ca5SDavid du Colombier 		i = 18;
97459cc4ca5SDavid du Colombier 		ndigits = 0;
97559cc4ca5SDavid du Colombier 		break;
97659cc4ca5SDavid du Colombier 	case 2:
97759cc4ca5SDavid du Colombier 		leftright = 0;
97859cc4ca5SDavid du Colombier 		/* no break */
97959cc4ca5SDavid du Colombier 	case 4:
98059cc4ca5SDavid du Colombier 		if (ndigits <= 0)
98159cc4ca5SDavid du Colombier 			ndigits = 1;
98259cc4ca5SDavid du Colombier 		ilim = ilim1 = i = ndigits;
98359cc4ca5SDavid du Colombier 		break;
98459cc4ca5SDavid du Colombier 	case 3:
98559cc4ca5SDavid du Colombier 		leftright = 0;
98659cc4ca5SDavid du Colombier 		/* no break */
98759cc4ca5SDavid du Colombier 	case 5:
98859cc4ca5SDavid du Colombier 		i = ndigits + k + 1;
98959cc4ca5SDavid du Colombier 		ilim = i;
99059cc4ca5SDavid du Colombier 		ilim1 = i - 1;
99159cc4ca5SDavid du Colombier 		if (i <= 0)
99259cc4ca5SDavid du Colombier 			i = 1;
99359cc4ca5SDavid du Colombier 	}
99459cc4ca5SDavid du Colombier 	s = s0 = rv_alloc(i);
99559cc4ca5SDavid du Colombier 
99659cc4ca5SDavid du Colombier 	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
99759cc4ca5SDavid du Colombier 
99859cc4ca5SDavid du Colombier 		/* Try to get by with floating-point arithmetic. */
99959cc4ca5SDavid du Colombier 
100059cc4ca5SDavid du Colombier 		i = 0;
100159cc4ca5SDavid du Colombier 		d2 = d;
100259cc4ca5SDavid du Colombier 		k0 = k;
100359cc4ca5SDavid du Colombier 		ilim0 = ilim;
100459cc4ca5SDavid du Colombier 		ieps = 2; /* conservative */
100559cc4ca5SDavid du Colombier 		if (k > 0) {
100659cc4ca5SDavid du Colombier 			ds = tens[k&0xf];
100759cc4ca5SDavid du Colombier 			j = k >> 4;
100859cc4ca5SDavid du Colombier 			if (j & Bletch) {
100959cc4ca5SDavid du Colombier 				/* prevent overflows */
101059cc4ca5SDavid du Colombier 				j &= Bletch - 1;
101159cc4ca5SDavid du Colombier 				d /= bigtens[n_bigtens-1];
101259cc4ca5SDavid du Colombier 				ieps++;
101359cc4ca5SDavid du Colombier 			}
101459cc4ca5SDavid du Colombier 			for (; j; j >>= 1, i++)
101559cc4ca5SDavid du Colombier 				if (j & 1) {
101659cc4ca5SDavid du Colombier 					ieps++;
101759cc4ca5SDavid du Colombier 					ds *= bigtens[i];
101859cc4ca5SDavid du Colombier 				}
101959cc4ca5SDavid du Colombier 			d /= ds;
102059cc4ca5SDavid du Colombier 		} else if (j1 = -k) {
102159cc4ca5SDavid du Colombier 			d *= tens[j1 & 0xf];
102259cc4ca5SDavid du Colombier 			for (j = j1 >> 4; j; j >>= 1, i++)
102359cc4ca5SDavid du Colombier 				if (j & 1) {
102459cc4ca5SDavid du Colombier 					ieps++;
102559cc4ca5SDavid du Colombier 					d *= bigtens[i];
102659cc4ca5SDavid du Colombier 				}
102759cc4ca5SDavid du Colombier 		}
102859cc4ca5SDavid du Colombier 		if (k_check && d < 1. && ilim > 0) {
102959cc4ca5SDavid du Colombier 			if (ilim1 <= 0)
103059cc4ca5SDavid du Colombier 				goto fast_failed;
103159cc4ca5SDavid du Colombier 			ilim = ilim1;
103259cc4ca5SDavid du Colombier 			k--;
103359cc4ca5SDavid du Colombier 			d *= 10.;
103459cc4ca5SDavid du Colombier 			ieps++;
103559cc4ca5SDavid du Colombier 		}
103659cc4ca5SDavid du Colombier 		eps = ieps * d + 7.;
10378c242bd4SDavid du Colombier 
10388c242bd4SDavid du Colombier 		ulsd = double2ulongs(eps);
10398c242bd4SDavid du Colombier 		ulsd.hi -= (P - 1) * Exp_msk1;
10408c242bd4SDavid du Colombier 		eps = ulongs2double(ulsd);
10418c242bd4SDavid du Colombier 
104259cc4ca5SDavid du Colombier 		if (ilim == 0) {
104359cc4ca5SDavid du Colombier 			S = mhi = 0;
104459cc4ca5SDavid du Colombier 			d -= 5.;
104559cc4ca5SDavid du Colombier 			if (d > eps)
104659cc4ca5SDavid du Colombier 				goto one_digit;
104759cc4ca5SDavid du Colombier 			if (d < -eps)
104859cc4ca5SDavid du Colombier 				goto no_digits;
104959cc4ca5SDavid du Colombier 			goto fast_failed;
105059cc4ca5SDavid du Colombier 		}
105159cc4ca5SDavid du Colombier 		/* Generate ilim digits, then fix them up. */
105259cc4ca5SDavid du Colombier 		eps *= tens[ilim-1];
105359cc4ca5SDavid du Colombier 		for (i = 1; ; i++, d *= 10.) {
105459cc4ca5SDavid du Colombier 			L = d;
1055*eea45bbcSDavid du Colombier 			// assert(L < 10);
105659cc4ca5SDavid du Colombier 			d -= L;
105759cc4ca5SDavid du Colombier 			*s++ = '0' + (int)L;
105859cc4ca5SDavid du Colombier 			if (i == ilim) {
105959cc4ca5SDavid du Colombier 				if (d > 0.5 + eps)
106059cc4ca5SDavid du Colombier 					goto bump_up;
106159cc4ca5SDavid du Colombier 				else if (d < 0.5 - eps) {
106259cc4ca5SDavid du Colombier 					while (*--s == '0')
106359cc4ca5SDavid du Colombier 						;
106459cc4ca5SDavid du Colombier 					s++;
106559cc4ca5SDavid du Colombier 					goto ret1;
106659cc4ca5SDavid du Colombier 				}
106759cc4ca5SDavid du Colombier 				break;
106859cc4ca5SDavid du Colombier 			}
106959cc4ca5SDavid du Colombier 		}
107059cc4ca5SDavid du Colombier fast_failed:
107159cc4ca5SDavid du Colombier 		s = s0;
107259cc4ca5SDavid du Colombier 		d = d2;
107359cc4ca5SDavid du Colombier 		k = k0;
107459cc4ca5SDavid du Colombier 		ilim = ilim0;
107559cc4ca5SDavid du Colombier 	}
107659cc4ca5SDavid du Colombier 
107759cc4ca5SDavid du Colombier 	/* Do we have a "small" integer? */
107859cc4ca5SDavid du Colombier 
107959cc4ca5SDavid du Colombier 	if (be >= 0 && k <= Int_max) {
108059cc4ca5SDavid du Colombier 		/* Yes. */
108159cc4ca5SDavid du Colombier 		ds = tens[k];
108259cc4ca5SDavid du Colombier 		if (ndigits < 0 && ilim <= 0) {
108359cc4ca5SDavid du Colombier 			S = mhi = 0;
108459cc4ca5SDavid du Colombier 			if (ilim < 0 || d <= 5 * ds)
108559cc4ca5SDavid du Colombier 				goto no_digits;
108659cc4ca5SDavid du Colombier 			goto one_digit;
108759cc4ca5SDavid du Colombier 		}
108859cc4ca5SDavid du Colombier 		for (i = 1; ; i++) {
108959cc4ca5SDavid du Colombier 			L = d / ds;
109059cc4ca5SDavid du Colombier 			d -= L * ds;
109159cc4ca5SDavid du Colombier 			*s++ = '0' + (int)L;
109259cc4ca5SDavid du Colombier 			if (i == ilim) {
109359cc4ca5SDavid du Colombier 				d += d;
109459cc4ca5SDavid du Colombier 				if (d > ds || d == ds && L & 1) {
109559cc4ca5SDavid du Colombier bump_up:
109659cc4ca5SDavid du Colombier 					while (*--s == '9')
109759cc4ca5SDavid du Colombier 						if (s == s0) {
109859cc4ca5SDavid du Colombier 							k++;
109959cc4ca5SDavid du Colombier 							*s = '0';
110059cc4ca5SDavid du Colombier 							break;
110159cc4ca5SDavid du Colombier 						}
110259cc4ca5SDavid du Colombier 					++ * s++;
110359cc4ca5SDavid du Colombier 				}
110459cc4ca5SDavid du Colombier 				break;
110559cc4ca5SDavid du Colombier 			}
110659cc4ca5SDavid du Colombier 			if (!(d *= 10.))
110759cc4ca5SDavid du Colombier 				break;
110859cc4ca5SDavid du Colombier 		}
110959cc4ca5SDavid du Colombier 		goto ret1;
111059cc4ca5SDavid du Colombier 	}
111159cc4ca5SDavid du Colombier 
111259cc4ca5SDavid du Colombier 	m2 = b2;
111359cc4ca5SDavid du Colombier 	m5 = b5;
111459cc4ca5SDavid du Colombier 	mhi = mlo = 0;
111559cc4ca5SDavid du Colombier 	if (leftright) {
111659cc4ca5SDavid du Colombier 		if (mode < 2) {
111759cc4ca5SDavid du Colombier 			i =
111859cc4ca5SDavid du Colombier 			    1 + P - bbits;
111959cc4ca5SDavid du Colombier 		} else {
112059cc4ca5SDavid du Colombier 			j = ilim - 1;
112159cc4ca5SDavid du Colombier 			if (m5 >= j)
112259cc4ca5SDavid du Colombier 				m5 -= j;
112359cc4ca5SDavid du Colombier 			else {
112459cc4ca5SDavid du Colombier 				s5 += j -= m5;
112559cc4ca5SDavid du Colombier 				b5 += j;
112659cc4ca5SDavid du Colombier 				m5 = 0;
112759cc4ca5SDavid du Colombier 			}
112859cc4ca5SDavid du Colombier 			if ((i = ilim) < 0) {
112959cc4ca5SDavid du Colombier 				m2 -= i;
113059cc4ca5SDavid du Colombier 				i = 0;
113159cc4ca5SDavid du Colombier 			}
113259cc4ca5SDavid du Colombier 		}
113359cc4ca5SDavid du Colombier 		b2 += i;
113459cc4ca5SDavid du Colombier 		s2 += i;
113559cc4ca5SDavid du Colombier 		mhi = i2b(1);
113659cc4ca5SDavid du Colombier 	}
113759cc4ca5SDavid du Colombier 	if (m2 > 0 && s2 > 0) {
113859cc4ca5SDavid du Colombier 		i = m2 < s2 ? m2 : s2;
113959cc4ca5SDavid du Colombier 		b2 -= i;
114059cc4ca5SDavid du Colombier 		m2 -= i;
114159cc4ca5SDavid du Colombier 		s2 -= i;
114259cc4ca5SDavid du Colombier 	}
114359cc4ca5SDavid du Colombier 	if (b5 > 0) {
114459cc4ca5SDavid du Colombier 		if (leftright) {
114559cc4ca5SDavid du Colombier 			if (m5 > 0) {
114659cc4ca5SDavid du Colombier 				mhi = pow5mult(mhi, m5);
114759cc4ca5SDavid du Colombier 				b1 = mult(mhi, b);
114859cc4ca5SDavid du Colombier 				Bfree(b);
114959cc4ca5SDavid du Colombier 				b = b1;
115059cc4ca5SDavid du Colombier 			}
115159cc4ca5SDavid du Colombier 			if (j = b5 - m5)
115259cc4ca5SDavid du Colombier 				b = pow5mult(b, j);
115359cc4ca5SDavid du Colombier 		} else
115459cc4ca5SDavid du Colombier 			b = pow5mult(b, b5);
115559cc4ca5SDavid du Colombier 	}
115659cc4ca5SDavid du Colombier 	S = i2b(1);
115759cc4ca5SDavid du Colombier 	if (s5 > 0)
115859cc4ca5SDavid du Colombier 		S = pow5mult(S, s5);
115959cc4ca5SDavid du Colombier 
116059cc4ca5SDavid du Colombier 	/* Check for special case that d is a normalized power of 2. */
116159cc4ca5SDavid du Colombier 
116259cc4ca5SDavid du Colombier 	spec_case = 0;
116359cc4ca5SDavid du Colombier 	if (mode < 2) {
11648c242bd4SDavid du Colombier 		ulsd = double2ulongs(d);
11658c242bd4SDavid du Colombier 		if (!ulsd.lo && !(ulsd.hi & Bndry_mask)) {
116659cc4ca5SDavid du Colombier 			/* The special case */
116759cc4ca5SDavid du Colombier 			b2 += Log2P;
116859cc4ca5SDavid du Colombier 			s2 += Log2P;
116959cc4ca5SDavid du Colombier 			spec_case = 1;
117059cc4ca5SDavid du Colombier 		}
117159cc4ca5SDavid du Colombier 	}
117259cc4ca5SDavid du Colombier 
117359cc4ca5SDavid du Colombier 	/* Arrange for convenient computation of quotients:
117459cc4ca5SDavid du Colombier 	 * shift left if necessary so divisor has 4 leading 0 bits.
117559cc4ca5SDavid du Colombier 	 *
117659cc4ca5SDavid du Colombier 	 * Perhaps we should just compute leading 28 bits of S once
117759cc4ca5SDavid du Colombier 	 * and for all and pass them and a shift to quorem, so it
117859cc4ca5SDavid du Colombier 	 * can do shifts and ors to compute the numerator for q.
117959cc4ca5SDavid du Colombier 	 */
118059cc4ca5SDavid du Colombier 	if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)
118159cc4ca5SDavid du Colombier 		i = 32 - i;
118259cc4ca5SDavid du Colombier 	if (i > 4) {
118359cc4ca5SDavid du Colombier 		i -= 4;
118459cc4ca5SDavid du Colombier 		b2 += i;
118559cc4ca5SDavid du Colombier 		m2 += i;
118659cc4ca5SDavid du Colombier 		s2 += i;
118759cc4ca5SDavid du Colombier 	} else if (i < 4) {
118859cc4ca5SDavid du Colombier 		i += 28;
118959cc4ca5SDavid du Colombier 		b2 += i;
119059cc4ca5SDavid du Colombier 		m2 += i;
119159cc4ca5SDavid du Colombier 		s2 += i;
119259cc4ca5SDavid du Colombier 	}
119359cc4ca5SDavid du Colombier 	if (b2 > 0)
119459cc4ca5SDavid du Colombier 		b = lshift(b, b2);
119559cc4ca5SDavid du Colombier 	if (s2 > 0)
119659cc4ca5SDavid du Colombier 		S = lshift(S, s2);
119759cc4ca5SDavid du Colombier 	if (k_check) {
119859cc4ca5SDavid du Colombier 		if (cmp(b, S) < 0) {
119959cc4ca5SDavid du Colombier 			k--;
120059cc4ca5SDavid du Colombier 			b = multadd(b, 10, 0);	/* we botched the k estimate */
120159cc4ca5SDavid du Colombier 			if (leftright)
120259cc4ca5SDavid du Colombier 				mhi = multadd(mhi, 10, 0);
120359cc4ca5SDavid du Colombier 			ilim = ilim1;
120459cc4ca5SDavid du Colombier 		}
120559cc4ca5SDavid du Colombier 	}
120659cc4ca5SDavid du Colombier 	if (ilim <= 0 && mode > 2) {
120759cc4ca5SDavid du Colombier 		if (ilim < 0 || cmp(b, S = multadd(S, 5, 0)) <= 0) {
120859cc4ca5SDavid du Colombier 			/* no digits, fcvt style */
120959cc4ca5SDavid du Colombier no_digits:
121059cc4ca5SDavid du Colombier 			k = -1 - ndigits;
121159cc4ca5SDavid du Colombier 			goto ret;
121259cc4ca5SDavid du Colombier 		}
121359cc4ca5SDavid du Colombier one_digit:
121459cc4ca5SDavid du Colombier 		*s++ = '1';
121559cc4ca5SDavid du Colombier 		k++;
121659cc4ca5SDavid du Colombier 		goto ret;
121759cc4ca5SDavid du Colombier 	}
121859cc4ca5SDavid du Colombier 	if (leftright) {
121959cc4ca5SDavid du Colombier 		if (m2 > 0)
122059cc4ca5SDavid du Colombier 			mhi = lshift(mhi, m2);
122159cc4ca5SDavid du Colombier 
122259cc4ca5SDavid du Colombier 		/* Compute mlo -- check for special case
122359cc4ca5SDavid du Colombier 		 * that d is a normalized power of 2.
122459cc4ca5SDavid du Colombier 		 */
122559cc4ca5SDavid du Colombier 
122659cc4ca5SDavid du Colombier 		mlo = mhi;
122759cc4ca5SDavid du Colombier 		if (spec_case) {
122859cc4ca5SDavid du Colombier 			mhi = Balloc(mhi->k);
122959cc4ca5SDavid du Colombier 			Bcopy(mhi, mlo);
123059cc4ca5SDavid du Colombier 			mhi = lshift(mhi, Log2P);
123159cc4ca5SDavid du Colombier 		}
123259cc4ca5SDavid du Colombier 
123359cc4ca5SDavid du Colombier 		for (i = 1; ; i++) {
123459cc4ca5SDavid du Colombier 			dig = quorem(b, S) + '0';
123559cc4ca5SDavid du Colombier 			/* Do we yet have the shortest decimal string
123659cc4ca5SDavid du Colombier 			 * that will round to d?
123759cc4ca5SDavid du Colombier 			 */
123859cc4ca5SDavid du Colombier 			j = cmp(b, mlo);
123959cc4ca5SDavid du Colombier 			delta = diff(S, mhi);
124059cc4ca5SDavid du Colombier 			j1 = delta->sign ? 1 : cmp(b, delta);
124159cc4ca5SDavid du Colombier 			Bfree(delta);
12428c242bd4SDavid du Colombier 			ulsd = double2ulongs(d);
12438c242bd4SDavid du Colombier 			if (j1 == 0 && !mode && !(ulsd.lo & 1)) {
124459cc4ca5SDavid du Colombier 				if (dig == '9')
124559cc4ca5SDavid du Colombier 					goto round_9_up;
124659cc4ca5SDavid du Colombier 				if (j > 0)
124759cc4ca5SDavid du Colombier 					dig++;
124859cc4ca5SDavid du Colombier 				*s++ = dig;
124959cc4ca5SDavid du Colombier 				goto ret;
125059cc4ca5SDavid du Colombier 			}
12518c242bd4SDavid du Colombier 			if (j < 0 || j == 0 && !mode && !(ulsd.lo & 1)) {
125259cc4ca5SDavid du Colombier 				if (j1 > 0) {
125359cc4ca5SDavid du Colombier 					b = lshift(b, 1);
125459cc4ca5SDavid du Colombier 					j1 = cmp(b, S);
125559cc4ca5SDavid du Colombier 					if ((j1 > 0 || j1 == 0 && dig & 1)
125659cc4ca5SDavid du Colombier 					     && dig++ == '9')
125759cc4ca5SDavid du Colombier 						goto round_9_up;
125859cc4ca5SDavid du Colombier 				}
125959cc4ca5SDavid du Colombier 				*s++ = dig;
126059cc4ca5SDavid du Colombier 				goto ret;
126159cc4ca5SDavid du Colombier 			}
126259cc4ca5SDavid du Colombier 			if (j1 > 0) {
126359cc4ca5SDavid du Colombier 				if (dig == '9') { /* possible if i == 1 */
126459cc4ca5SDavid du Colombier round_9_up:
126559cc4ca5SDavid du Colombier 					*s++ = '9';
126659cc4ca5SDavid du Colombier 					goto roundoff;
126759cc4ca5SDavid du Colombier 				}
126859cc4ca5SDavid du Colombier 				*s++ = dig + 1;
126959cc4ca5SDavid du Colombier 				goto ret;
127059cc4ca5SDavid du Colombier 			}
127159cc4ca5SDavid du Colombier 			*s++ = dig;
127259cc4ca5SDavid du Colombier 			if (i == ilim)
127359cc4ca5SDavid du Colombier 				break;
127459cc4ca5SDavid du Colombier 			b = multadd(b, 10, 0);
127559cc4ca5SDavid du Colombier 			if (mlo == mhi)
127659cc4ca5SDavid du Colombier 				mlo = mhi = multadd(mhi, 10, 0);
127759cc4ca5SDavid du Colombier 			else {
127859cc4ca5SDavid du Colombier 				mlo = multadd(mlo, 10, 0);
127959cc4ca5SDavid du Colombier 				mhi = multadd(mhi, 10, 0);
128059cc4ca5SDavid du Colombier 			}
128159cc4ca5SDavid du Colombier 		}
128259cc4ca5SDavid du Colombier 	} else
128359cc4ca5SDavid du Colombier 		for (i = 1; ; i++) {
128459cc4ca5SDavid du Colombier 			*s++ = dig = quorem(b, S) + '0';
128559cc4ca5SDavid du Colombier 			if (i >= ilim)
128659cc4ca5SDavid du Colombier 				break;
128759cc4ca5SDavid du Colombier 			b = multadd(b, 10, 0);
128859cc4ca5SDavid du Colombier 		}
128959cc4ca5SDavid du Colombier 
129059cc4ca5SDavid du Colombier 	/* Round off last digit */
129159cc4ca5SDavid du Colombier 
129259cc4ca5SDavid du Colombier 	b = lshift(b, 1);
129359cc4ca5SDavid du Colombier 	j = cmp(b, S);
129459cc4ca5SDavid du Colombier 	if (j > 0 || j == 0 && dig & 1) {
129559cc4ca5SDavid du Colombier roundoff:
129659cc4ca5SDavid du Colombier 		while (*--s == '9')
129759cc4ca5SDavid du Colombier 			if (s == s0) {
129859cc4ca5SDavid du Colombier 				k++;
129959cc4ca5SDavid du Colombier 				*s++ = '1';
130059cc4ca5SDavid du Colombier 				goto ret;
130159cc4ca5SDavid du Colombier 			}
130259cc4ca5SDavid du Colombier 		++ * s++;
130359cc4ca5SDavid du Colombier 	} else {
130459cc4ca5SDavid du Colombier 		while (*--s == '0')
130559cc4ca5SDavid du Colombier 			;
130659cc4ca5SDavid du Colombier 		s++;
130759cc4ca5SDavid du Colombier 	}
130859cc4ca5SDavid du Colombier ret:
130959cc4ca5SDavid du Colombier 	Bfree(S);
131059cc4ca5SDavid du Colombier 	if (mhi) {
131159cc4ca5SDavid du Colombier 		if (mlo && mlo != mhi)
131259cc4ca5SDavid du Colombier 			Bfree(mlo);
131359cc4ca5SDavid du Colombier 		Bfree(mhi);
131459cc4ca5SDavid du Colombier 	}
131559cc4ca5SDavid du Colombier ret1:
131659cc4ca5SDavid du Colombier 	Bfree(b);
131759cc4ca5SDavid du Colombier 	*s = 0;
131859cc4ca5SDavid du Colombier 	*decpt = k + 1;
131959cc4ca5SDavid du Colombier 	if (rve)
132059cc4ca5SDavid du Colombier 		*rve = s;
132159cc4ca5SDavid du Colombier 	return s0;
132259cc4ca5SDavid du Colombier }
1323