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