13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
359cc4ca5SDavid du Colombier #include <ctype.h>
43e12c5d1SDavid du Colombier
559cc4ca5SDavid du Colombier /*
659cc4ca5SDavid du Colombier * This routine will convert to arbitrary precision
759cc4ca5SDavid du Colombier * floating point entirely in multi-precision fixed.
859cc4ca5SDavid du Colombier * The answer is the closest floating point number to
959cc4ca5SDavid du Colombier * the given decimal number. Exactly half way are
1059cc4ca5SDavid du Colombier * rounded ala ieee rules.
1159cc4ca5SDavid du Colombier * Method is to scale input decimal between .500 and .999...
1259cc4ca5SDavid du Colombier * with external power of 2, then binary search for the
1359cc4ca5SDavid du Colombier * closest mantissa to this decimal number.
1459cc4ca5SDavid du Colombier * Nmant is is the required precision. (53 for ieee dp)
1559cc4ca5SDavid du Colombier * Nbits is the max number of bits/word. (must be <= 28)
1659cc4ca5SDavid du Colombier * Prec is calculated - the number of words of fixed mantissa.
1759cc4ca5SDavid du Colombier */
1859cc4ca5SDavid du Colombier enum
193e12c5d1SDavid du Colombier {
2059cc4ca5SDavid du Colombier Nbits = 28, // bits safely represented in a ulong
2159cc4ca5SDavid du Colombier Nmant = 53, // bits of precision required
22*9a747e4fSDavid du Colombier Bias = 1022,
2359cc4ca5SDavid du Colombier Prec = (Nmant+Nbits+1)/Nbits, // words of Nbits each to represent mantissa
2459cc4ca5SDavid du Colombier Sigbit = 1<<(Prec*Nbits-Nmant), // first significant bit of Prec-th word
2559cc4ca5SDavid du Colombier Ndig = 1500,
2659cc4ca5SDavid du Colombier One = (ulong)(1<<Nbits),
2759cc4ca5SDavid du Colombier Half = (ulong)(One>>1),
2859cc4ca5SDavid du Colombier Maxe = 310,
2959cc4ca5SDavid du Colombier Fsign = 1<<0, // found -
3059cc4ca5SDavid du Colombier Fesign = 1<<1, // found e-
3159cc4ca5SDavid du Colombier Fdpoint = 1<<2, // found .
3259cc4ca5SDavid du Colombier
3359cc4ca5SDavid du Colombier S0 = 0, // _ _S0 +S1 #S2 .S3
3459cc4ca5SDavid du Colombier S1, // _+ #S2 .S3
3559cc4ca5SDavid du Colombier S2, // _+# #S2 .S4 eS5
3659cc4ca5SDavid du Colombier S3, // _+. #S4
3759cc4ca5SDavid du Colombier S4, // _+#.# #S4 eS5
3859cc4ca5SDavid du Colombier S5, // _+#.#e +S6 #S7
3959cc4ca5SDavid du Colombier S6, // _+#.#e+ #S7
4059cc4ca5SDavid du Colombier S7, // _+#.#e+# #S7
4159cc4ca5SDavid du Colombier };
4259cc4ca5SDavid du Colombier
4359cc4ca5SDavid du Colombier static int xcmp(char*, char*);
4459cc4ca5SDavid du Colombier static int fpcmp(char*, ulong*);
4559cc4ca5SDavid du Colombier static void frnorm(ulong*);
4659cc4ca5SDavid du Colombier static void divascii(char*, int*, int*, int*);
4759cc4ca5SDavid du Colombier static void mulascii(char*, int*, int*, int*);
48*9a747e4fSDavid du Colombier static void divby(char*, int*, int);
4959cc4ca5SDavid du Colombier
5059cc4ca5SDavid du Colombier typedef struct Tab Tab;
5159cc4ca5SDavid du Colombier struct Tab
5259cc4ca5SDavid du Colombier {
5359cc4ca5SDavid du Colombier int bp;
5459cc4ca5SDavid du Colombier int siz;
5559cc4ca5SDavid du Colombier char* cmp;
5659cc4ca5SDavid du Colombier };
573e12c5d1SDavid du Colombier
583e12c5d1SDavid du Colombier double
strtod(char * as,char ** aas)5959cc4ca5SDavid du Colombier strtod(char *as, char **aas)
603e12c5d1SDavid du Colombier {
61*9a747e4fSDavid du Colombier int na, ona, ex, dp, bp, c, i, flag, state;
62*9a747e4fSDavid du Colombier ulong low[Prec], hig[Prec], mid[Prec], num, den;
633e12c5d1SDavid du Colombier double d;
6459cc4ca5SDavid du Colombier char *s, a[Ndig];
653e12c5d1SDavid du Colombier
6659cc4ca5SDavid du Colombier flag = 0; // Fsign, Fesign, Fdpoint
6759cc4ca5SDavid du Colombier na = 0; // number of digits of a[]
6859cc4ca5SDavid du Colombier dp = 0; // na of decimal point
6959cc4ca5SDavid du Colombier ex = 0; // exonent
7059cc4ca5SDavid du Colombier
7159cc4ca5SDavid du Colombier state = S0;
7259cc4ca5SDavid du Colombier for(s=as;; s++) {
7359cc4ca5SDavid du Colombier c = *s;
7459cc4ca5SDavid du Colombier if(c >= '0' && c <= '9') {
7559cc4ca5SDavid du Colombier switch(state) {
7659cc4ca5SDavid du Colombier case S0:
7759cc4ca5SDavid du Colombier case S1:
7859cc4ca5SDavid du Colombier case S2:
7959cc4ca5SDavid du Colombier state = S2;
803e12c5d1SDavid du Colombier break;
8159cc4ca5SDavid du Colombier case S3:
8259cc4ca5SDavid du Colombier case S4:
8359cc4ca5SDavid du Colombier state = S4;
8459cc4ca5SDavid du Colombier break;
8559cc4ca5SDavid du Colombier
8659cc4ca5SDavid du Colombier case S5:
8759cc4ca5SDavid du Colombier case S6:
8859cc4ca5SDavid du Colombier case S7:
8959cc4ca5SDavid du Colombier state = S7;
9059cc4ca5SDavid du Colombier ex = ex*10 + (c-'0');
9159cc4ca5SDavid du Colombier continue;
923e12c5d1SDavid du Colombier }
9359cc4ca5SDavid du Colombier if(na == 0 && c == '0') {
9459cc4ca5SDavid du Colombier dp--;
9559cc4ca5SDavid du Colombier continue;
963e12c5d1SDavid du Colombier }
9759cc4ca5SDavid du Colombier if(na < Ndig-50)
9859cc4ca5SDavid du Colombier a[na++] = c;
9959cc4ca5SDavid du Colombier continue;
10059cc4ca5SDavid du Colombier }
10159cc4ca5SDavid du Colombier switch(c) {
10259cc4ca5SDavid du Colombier case '\t':
10359cc4ca5SDavid du Colombier case '\n':
10459cc4ca5SDavid du Colombier case '\v':
10559cc4ca5SDavid du Colombier case '\f':
10659cc4ca5SDavid du Colombier case '\r':
10759cc4ca5SDavid du Colombier case ' ':
10859cc4ca5SDavid du Colombier if(state == S0)
10959cc4ca5SDavid du Colombier continue;
11059cc4ca5SDavid du Colombier break;
11159cc4ca5SDavid du Colombier case '-':
11259cc4ca5SDavid du Colombier if(state == S0)
11359cc4ca5SDavid du Colombier flag |= Fsign;
11459cc4ca5SDavid du Colombier else
11559cc4ca5SDavid du Colombier flag |= Fesign;
11659cc4ca5SDavid du Colombier case '+':
11759cc4ca5SDavid du Colombier if(state == S0)
11859cc4ca5SDavid du Colombier state = S1;
11959cc4ca5SDavid du Colombier else
12059cc4ca5SDavid du Colombier if(state == S5)
12159cc4ca5SDavid du Colombier state = S6;
12259cc4ca5SDavid du Colombier else
12359cc4ca5SDavid du Colombier break; // syntax
12459cc4ca5SDavid du Colombier continue;
12559cc4ca5SDavid du Colombier case '.':
12659cc4ca5SDavid du Colombier flag |= Fdpoint;
12759cc4ca5SDavid du Colombier dp = na;
12859cc4ca5SDavid du Colombier if(state == S0 || state == S1) {
12959cc4ca5SDavid du Colombier state = S3;
13059cc4ca5SDavid du Colombier continue;
13159cc4ca5SDavid du Colombier }
13259cc4ca5SDavid du Colombier if(state == S2) {
13359cc4ca5SDavid du Colombier state = S4;
13459cc4ca5SDavid du Colombier continue;
13559cc4ca5SDavid du Colombier }
13659cc4ca5SDavid du Colombier break;
13759cc4ca5SDavid du Colombier case 'e':
13859cc4ca5SDavid du Colombier case 'E':
13959cc4ca5SDavid du Colombier if(state == S2 || state == S4) {
14059cc4ca5SDavid du Colombier state = S5;
14159cc4ca5SDavid du Colombier continue;
14259cc4ca5SDavid du Colombier }
14359cc4ca5SDavid du Colombier break;
14459cc4ca5SDavid du Colombier }
14559cc4ca5SDavid du Colombier break;
14659cc4ca5SDavid du Colombier }
14759cc4ca5SDavid du Colombier
14859cc4ca5SDavid du Colombier /*
14959cc4ca5SDavid du Colombier * clean up return char-pointer
15059cc4ca5SDavid du Colombier */
15159cc4ca5SDavid du Colombier switch(state) {
15259cc4ca5SDavid du Colombier case S0:
15359cc4ca5SDavid du Colombier if(xcmp(s, "nan") == 0) {
15459cc4ca5SDavid du Colombier if(aas != nil)
15559cc4ca5SDavid du Colombier *aas = s+3;
15659cc4ca5SDavid du Colombier goto retnan;
15759cc4ca5SDavid du Colombier }
15859cc4ca5SDavid du Colombier case S1:
15959cc4ca5SDavid du Colombier if(xcmp(s, "infinity") == 0) {
16059cc4ca5SDavid du Colombier if(aas != nil)
16159cc4ca5SDavid du Colombier *aas = s+8;
16259cc4ca5SDavid du Colombier goto retinf;
16359cc4ca5SDavid du Colombier }
16459cc4ca5SDavid du Colombier if(xcmp(s, "inf") == 0) {
16559cc4ca5SDavid du Colombier if(aas != nil)
16659cc4ca5SDavid du Colombier *aas = s+3;
16759cc4ca5SDavid du Colombier goto retinf;
16859cc4ca5SDavid du Colombier }
16959cc4ca5SDavid du Colombier case S3:
17059cc4ca5SDavid du Colombier if(aas != nil)
17159cc4ca5SDavid du Colombier *aas = as;
17259cc4ca5SDavid du Colombier goto ret0; // no digits found
17359cc4ca5SDavid du Colombier case S6:
17459cc4ca5SDavid du Colombier s--; // back over +-
17559cc4ca5SDavid du Colombier case S5:
17659cc4ca5SDavid du Colombier s--; // back over e
17759cc4ca5SDavid du Colombier break;
17859cc4ca5SDavid du Colombier }
17959cc4ca5SDavid du Colombier if(aas != nil)
18059cc4ca5SDavid du Colombier *aas = s;
18159cc4ca5SDavid du Colombier
18259cc4ca5SDavid du Colombier if(flag & Fdpoint)
18359cc4ca5SDavid du Colombier while(na > 0 && a[na-1] == '0')
18459cc4ca5SDavid du Colombier na--;
18559cc4ca5SDavid du Colombier if(na == 0)
18659cc4ca5SDavid du Colombier goto ret0; // zero
18759cc4ca5SDavid du Colombier a[na] = 0;
18859cc4ca5SDavid du Colombier if(!(flag & Fdpoint))
18959cc4ca5SDavid du Colombier dp = na;
19059cc4ca5SDavid du Colombier if(flag & Fesign)
19159cc4ca5SDavid du Colombier ex = -ex;
19259cc4ca5SDavid du Colombier dp += ex;
193*9a747e4fSDavid du Colombier if(dp < -Maxe-Nmant/3) /* actually -Nmant*log(2)/log(10), but Nmant/3 close enough */
19459cc4ca5SDavid du Colombier goto ret0; // underflow by exp
19559cc4ca5SDavid du Colombier else
19659cc4ca5SDavid du Colombier if(dp > +Maxe)
19759cc4ca5SDavid du Colombier goto retinf; // overflow by exp
19859cc4ca5SDavid du Colombier
19959cc4ca5SDavid du Colombier /*
20059cc4ca5SDavid du Colombier * normalize the decimal ascii number
20159cc4ca5SDavid du Colombier * to range .[5-9][0-9]* e0
20259cc4ca5SDavid du Colombier */
20359cc4ca5SDavid du Colombier bp = 0; // binary exponent
20459cc4ca5SDavid du Colombier while(dp > 0)
20559cc4ca5SDavid du Colombier divascii(a, &na, &dp, &bp);
20659cc4ca5SDavid du Colombier while(dp < 0 || a[0] < '5')
20759cc4ca5SDavid du Colombier mulascii(a, &na, &dp, &bp);
208*9a747e4fSDavid du Colombier a[na] = 0;
209*9a747e4fSDavid du Colombier
210*9a747e4fSDavid du Colombier /*
211*9a747e4fSDavid du Colombier * very small numbers are represented using
212*9a747e4fSDavid du Colombier * bp = -Bias+1. adjust accordingly.
213*9a747e4fSDavid du Colombier */
214*9a747e4fSDavid du Colombier if(bp < -Bias+1){
215*9a747e4fSDavid du Colombier ona = na;
216*9a747e4fSDavid du Colombier divby(a, &na, -bp-Bias+1);
217*9a747e4fSDavid du Colombier if(na < ona){
218*9a747e4fSDavid du Colombier memmove(a+ona-na, a, na);
219*9a747e4fSDavid du Colombier memset(a, '0', ona-na);
220*9a747e4fSDavid du Colombier na = ona;
221*9a747e4fSDavid du Colombier }
222*9a747e4fSDavid du Colombier a[na] = 0;
223*9a747e4fSDavid du Colombier bp = -Bias+1;
224*9a747e4fSDavid du Colombier }
22559cc4ca5SDavid du Colombier
22659cc4ca5SDavid du Colombier /* close approx by naive conversion */
227*9a747e4fSDavid du Colombier num = 0;
228*9a747e4fSDavid du Colombier den = 1;
229*9a747e4fSDavid du Colombier for(i=0; i<9 && (c=a[i]); i++) {
230*9a747e4fSDavid du Colombier num = num*10 + (c-'0');
231*9a747e4fSDavid du Colombier den *= 10;
23259cc4ca5SDavid du Colombier }
233*9a747e4fSDavid du Colombier low[0] = umuldiv(num, One, den);
234*9a747e4fSDavid du Colombier hig[0] = umuldiv(num+1, One, den);
23559cc4ca5SDavid du Colombier for(i=1; i<Prec; i++) {
23659cc4ca5SDavid du Colombier low[i] = 0;
23759cc4ca5SDavid du Colombier hig[i] = One-1;
23859cc4ca5SDavid du Colombier }
23959cc4ca5SDavid du Colombier
24059cc4ca5SDavid du Colombier /* binary search for closest mantissa */
24159cc4ca5SDavid du Colombier for(;;) {
24259cc4ca5SDavid du Colombier /* mid = (hig + low) / 2 */
24359cc4ca5SDavid du Colombier c = 0;
24459cc4ca5SDavid du Colombier for(i=0; i<Prec; i++) {
24559cc4ca5SDavid du Colombier mid[i] = hig[i] + low[i];
24659cc4ca5SDavid du Colombier if(c)
24759cc4ca5SDavid du Colombier mid[i] += One;
24859cc4ca5SDavid du Colombier c = mid[i] & 1;
24959cc4ca5SDavid du Colombier mid[i] >>= 1;
25059cc4ca5SDavid du Colombier }
25159cc4ca5SDavid du Colombier frnorm(mid);
25259cc4ca5SDavid du Colombier
25359cc4ca5SDavid du Colombier /* compare */
25459cc4ca5SDavid du Colombier c = fpcmp(a, mid);
25559cc4ca5SDavid du Colombier if(c > 0) {
25659cc4ca5SDavid du Colombier c = 1;
25759cc4ca5SDavid du Colombier for(i=0; i<Prec; i++)
25859cc4ca5SDavid du Colombier if(low[i] != mid[i]) {
25959cc4ca5SDavid du Colombier c = 0;
26059cc4ca5SDavid du Colombier low[i] = mid[i];
26159cc4ca5SDavid du Colombier }
26259cc4ca5SDavid du Colombier if(c)
26359cc4ca5SDavid du Colombier break; // between mid and hig
26459cc4ca5SDavid du Colombier continue;
26559cc4ca5SDavid du Colombier }
26659cc4ca5SDavid du Colombier if(c < 0) {
26759cc4ca5SDavid du Colombier for(i=0; i<Prec; i++)
26859cc4ca5SDavid du Colombier hig[i] = mid[i];
26959cc4ca5SDavid du Colombier continue;
27059cc4ca5SDavid du Colombier }
27159cc4ca5SDavid du Colombier
27259cc4ca5SDavid du Colombier /* only hard part is if even/odd roundings wants to go up */
27359cc4ca5SDavid du Colombier c = mid[Prec-1] & (Sigbit-1);
27459cc4ca5SDavid du Colombier if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
27559cc4ca5SDavid du Colombier mid[Prec-1] -= c;
27659cc4ca5SDavid du Colombier break; // exactly mid
27759cc4ca5SDavid du Colombier }
27859cc4ca5SDavid du Colombier
27959cc4ca5SDavid du Colombier /* normal rounding applies */
28059cc4ca5SDavid du Colombier c = mid[Prec-1] & (Sigbit-1);
28159cc4ca5SDavid du Colombier mid[Prec-1] -= c;
28259cc4ca5SDavid du Colombier if(c >= Sigbit/2) {
28359cc4ca5SDavid du Colombier mid[Prec-1] += Sigbit;
28459cc4ca5SDavid du Colombier frnorm(mid);
28559cc4ca5SDavid du Colombier }
286*9a747e4fSDavid du Colombier d = 0;
287*9a747e4fSDavid du Colombier for(i=0; i<Prec; i++)
288*9a747e4fSDavid du Colombier d = d*One + mid[i];
289*9a747e4fSDavid du Colombier if(flag & Fsign)
290*9a747e4fSDavid du Colombier d = -d;
291*9a747e4fSDavid du Colombier d = ldexp(d, bp - Prec*Nbits);
292*9a747e4fSDavid du Colombier return d;
29359cc4ca5SDavid du Colombier
29459cc4ca5SDavid du Colombier ret0:
29559cc4ca5SDavid du Colombier return 0;
29659cc4ca5SDavid du Colombier
29759cc4ca5SDavid du Colombier retnan:
29859cc4ca5SDavid du Colombier return NaN();
29959cc4ca5SDavid du Colombier
30059cc4ca5SDavid du Colombier retinf:
30159cc4ca5SDavid du Colombier if(flag & Fsign)
30259cc4ca5SDavid du Colombier return Inf(-1);
30359cc4ca5SDavid du Colombier return Inf(+1);
3043e12c5d1SDavid du Colombier }
30559cc4ca5SDavid du Colombier
30659cc4ca5SDavid du Colombier static void
frnorm(ulong * f)30759cc4ca5SDavid du Colombier frnorm(ulong *f)
30859cc4ca5SDavid du Colombier {
30959cc4ca5SDavid du Colombier int i, c;
31059cc4ca5SDavid du Colombier
31159cc4ca5SDavid du Colombier c = 0;
31259cc4ca5SDavid du Colombier for(i=Prec-1; i>0; i--) {
31359cc4ca5SDavid du Colombier f[i] += c;
31459cc4ca5SDavid du Colombier c = f[i] >> Nbits;
31559cc4ca5SDavid du Colombier f[i] &= One-1;
31659cc4ca5SDavid du Colombier }
31759cc4ca5SDavid du Colombier f[0] += c;
31859cc4ca5SDavid du Colombier }
31959cc4ca5SDavid du Colombier
32059cc4ca5SDavid du Colombier static int
fpcmp(char * a,ulong * f)32159cc4ca5SDavid du Colombier fpcmp(char *a, ulong* f)
32259cc4ca5SDavid du Colombier {
32359cc4ca5SDavid du Colombier ulong tf[Prec];
32459cc4ca5SDavid du Colombier int i, d, c;
32559cc4ca5SDavid du Colombier
32659cc4ca5SDavid du Colombier for(i=0; i<Prec; i++)
32759cc4ca5SDavid du Colombier tf[i] = f[i];
32859cc4ca5SDavid du Colombier
32959cc4ca5SDavid du Colombier for(;;) {
33059cc4ca5SDavid du Colombier /* tf *= 10 */
33159cc4ca5SDavid du Colombier for(i=0; i<Prec; i++)
33259cc4ca5SDavid du Colombier tf[i] = tf[i]*10;
33359cc4ca5SDavid du Colombier frnorm(tf);
33459cc4ca5SDavid du Colombier d = (tf[0] >> Nbits) + '0';
33559cc4ca5SDavid du Colombier tf[0] &= One-1;
33659cc4ca5SDavid du Colombier
33759cc4ca5SDavid du Colombier /* compare next digit */
33859cc4ca5SDavid du Colombier c = *a;
33959cc4ca5SDavid du Colombier if(c == 0) {
34059cc4ca5SDavid du Colombier if('0' < d)
34159cc4ca5SDavid du Colombier return -1;
34259cc4ca5SDavid du Colombier if(tf[0] != 0)
34359cc4ca5SDavid du Colombier goto cont;
34459cc4ca5SDavid du Colombier for(i=1; i<Prec; i++)
34559cc4ca5SDavid du Colombier if(tf[i] != 0)
34659cc4ca5SDavid du Colombier goto cont;
34759cc4ca5SDavid du Colombier return 0;
34859cc4ca5SDavid du Colombier }
34959cc4ca5SDavid du Colombier if(c > d)
35059cc4ca5SDavid du Colombier return +1;
35159cc4ca5SDavid du Colombier if(c < d)
35259cc4ca5SDavid du Colombier return -1;
35359cc4ca5SDavid du Colombier a++;
35459cc4ca5SDavid du Colombier cont:;
35559cc4ca5SDavid du Colombier }
35659cc4ca5SDavid du Colombier }
35759cc4ca5SDavid du Colombier
35859cc4ca5SDavid du Colombier static void
_divby(char * a,int * na,int b)359*9a747e4fSDavid du Colombier _divby(char *a, int *na, int b)
36059cc4ca5SDavid du Colombier {
36159cc4ca5SDavid du Colombier int n, c;
36259cc4ca5SDavid du Colombier char *p;
36359cc4ca5SDavid du Colombier
36459cc4ca5SDavid du Colombier p = a;
36559cc4ca5SDavid du Colombier n = 0;
36659cc4ca5SDavid du Colombier while(n>>b == 0) {
36759cc4ca5SDavid du Colombier c = *a++;
36859cc4ca5SDavid du Colombier if(c == 0) {
36959cc4ca5SDavid du Colombier while(n) {
37059cc4ca5SDavid du Colombier c = n*10;
37159cc4ca5SDavid du Colombier if(c>>b)
37259cc4ca5SDavid du Colombier break;
37359cc4ca5SDavid du Colombier n = c;
37459cc4ca5SDavid du Colombier }
37559cc4ca5SDavid du Colombier goto xx;
37659cc4ca5SDavid du Colombier }
37759cc4ca5SDavid du Colombier n = n*10 + c-'0';
37859cc4ca5SDavid du Colombier (*na)--;
37959cc4ca5SDavid du Colombier }
38059cc4ca5SDavid du Colombier for(;;) {
38159cc4ca5SDavid du Colombier c = n>>b;
38259cc4ca5SDavid du Colombier n -= c<<b;
38359cc4ca5SDavid du Colombier *p++ = c + '0';
38459cc4ca5SDavid du Colombier c = *a++;
38559cc4ca5SDavid du Colombier if(c == 0)
38659cc4ca5SDavid du Colombier break;
38759cc4ca5SDavid du Colombier n = n*10 + c-'0';
38859cc4ca5SDavid du Colombier }
38959cc4ca5SDavid du Colombier (*na)++;
39059cc4ca5SDavid du Colombier xx:
39159cc4ca5SDavid du Colombier while(n) {
39259cc4ca5SDavid du Colombier n = n*10;
39359cc4ca5SDavid du Colombier c = n>>b;
39459cc4ca5SDavid du Colombier n -= c<<b;
39559cc4ca5SDavid du Colombier *p++ = c + '0';
39659cc4ca5SDavid du Colombier (*na)++;
39759cc4ca5SDavid du Colombier }
39859cc4ca5SDavid du Colombier *p = 0;
39959cc4ca5SDavid du Colombier }
40059cc4ca5SDavid du Colombier
401*9a747e4fSDavid du Colombier static void
divby(char * a,int * na,int b)402*9a747e4fSDavid du Colombier divby(char *a, int *na, int b)
403*9a747e4fSDavid du Colombier {
404*9a747e4fSDavid du Colombier while(b > 9){
405*9a747e4fSDavid du Colombier _divby(a, na, 9);
406*9a747e4fSDavid du Colombier a[*na] = 0;
407*9a747e4fSDavid du Colombier b -= 9;
408*9a747e4fSDavid du Colombier }
409*9a747e4fSDavid du Colombier if(b > 0)
410*9a747e4fSDavid du Colombier _divby(a, na, b);
411*9a747e4fSDavid du Colombier }
412*9a747e4fSDavid du Colombier
41359cc4ca5SDavid du Colombier static Tab tab1[] =
41459cc4ca5SDavid du Colombier {
41559cc4ca5SDavid du Colombier 1, 0, "",
41659cc4ca5SDavid du Colombier 3, 1, "7",
41759cc4ca5SDavid du Colombier 6, 2, "63",
41859cc4ca5SDavid du Colombier 9, 3, "511",
41959cc4ca5SDavid du Colombier 13, 4, "8191",
42059cc4ca5SDavid du Colombier 16, 5, "65535",
42159cc4ca5SDavid du Colombier 19, 6, "524287",
42259cc4ca5SDavid du Colombier 23, 7, "8388607",
42359cc4ca5SDavid du Colombier 26, 8, "67108863",
42459cc4ca5SDavid du Colombier 27, 9, "134217727",
42559cc4ca5SDavid du Colombier };
42659cc4ca5SDavid du Colombier
42759cc4ca5SDavid du Colombier static void
divascii(char * a,int * na,int * dp,int * bp)42859cc4ca5SDavid du Colombier divascii(char *a, int *na, int *dp, int *bp)
42959cc4ca5SDavid du Colombier {
43059cc4ca5SDavid du Colombier int b, d;
43159cc4ca5SDavid du Colombier Tab *t;
43259cc4ca5SDavid du Colombier
43359cc4ca5SDavid du Colombier d = *dp;
43459cc4ca5SDavid du Colombier if(d >= nelem(tab1))
43559cc4ca5SDavid du Colombier d = nelem(tab1)-1;
43659cc4ca5SDavid du Colombier t = tab1 + d;
43759cc4ca5SDavid du Colombier b = t->bp;
43859cc4ca5SDavid du Colombier if(memcmp(a, t->cmp, t->siz) > 0)
43959cc4ca5SDavid du Colombier d--;
44059cc4ca5SDavid du Colombier *dp -= d;
44159cc4ca5SDavid du Colombier *bp += b;
44259cc4ca5SDavid du Colombier divby(a, na, b);
44359cc4ca5SDavid du Colombier }
44459cc4ca5SDavid du Colombier
44559cc4ca5SDavid du Colombier static void
mulby(char * a,char * p,char * q,int b)44659cc4ca5SDavid du Colombier mulby(char *a, char *p, char *q, int b)
44759cc4ca5SDavid du Colombier {
44859cc4ca5SDavid du Colombier int n, c;
44959cc4ca5SDavid du Colombier
45059cc4ca5SDavid du Colombier n = 0;
45159cc4ca5SDavid du Colombier *p = 0;
45259cc4ca5SDavid du Colombier for(;;) {
45359cc4ca5SDavid du Colombier q--;
45459cc4ca5SDavid du Colombier if(q < a)
45559cc4ca5SDavid du Colombier break;
45659cc4ca5SDavid du Colombier c = *q - '0';
45759cc4ca5SDavid du Colombier c = (c<<b) + n;
45859cc4ca5SDavid du Colombier n = c/10;
45959cc4ca5SDavid du Colombier c -= n*10;
46059cc4ca5SDavid du Colombier p--;
46159cc4ca5SDavid du Colombier *p = c + '0';
46259cc4ca5SDavid du Colombier }
46359cc4ca5SDavid du Colombier while(n) {
46459cc4ca5SDavid du Colombier c = n;
46559cc4ca5SDavid du Colombier n = c/10;
46659cc4ca5SDavid du Colombier c -= n*10;
46759cc4ca5SDavid du Colombier p--;
46859cc4ca5SDavid du Colombier *p = c + '0';
46959cc4ca5SDavid du Colombier }
47059cc4ca5SDavid du Colombier }
47159cc4ca5SDavid du Colombier
47259cc4ca5SDavid du Colombier static Tab tab2[] =
47359cc4ca5SDavid du Colombier {
47459cc4ca5SDavid du Colombier 1, 1, "", // dp = 0-0
47559cc4ca5SDavid du Colombier 3, 3, "125",
47659cc4ca5SDavid du Colombier 6, 5, "15625",
47759cc4ca5SDavid du Colombier 9, 7, "1953125",
47859cc4ca5SDavid du Colombier 13, 10, "1220703125",
47959cc4ca5SDavid du Colombier 16, 12, "152587890625",
48059cc4ca5SDavid du Colombier 19, 14, "19073486328125",
48159cc4ca5SDavid du Colombier 23, 17, "11920928955078125",
48259cc4ca5SDavid du Colombier 26, 19, "1490116119384765625",
48359cc4ca5SDavid du Colombier 27, 19, "7450580596923828125", // dp 8-9
48459cc4ca5SDavid du Colombier };
48559cc4ca5SDavid du Colombier
48659cc4ca5SDavid du Colombier static void
mulascii(char * a,int * na,int * dp,int * bp)48759cc4ca5SDavid du Colombier mulascii(char *a, int *na, int *dp, int *bp)
48859cc4ca5SDavid du Colombier {
48959cc4ca5SDavid du Colombier char *p;
49059cc4ca5SDavid du Colombier int d, b;
49159cc4ca5SDavid du Colombier Tab *t;
49259cc4ca5SDavid du Colombier
49359cc4ca5SDavid du Colombier d = -*dp;
49459cc4ca5SDavid du Colombier if(d >= nelem(tab2))
49559cc4ca5SDavid du Colombier d = nelem(tab2)-1;
49659cc4ca5SDavid du Colombier t = tab2 + d;
49759cc4ca5SDavid du Colombier b = t->bp;
49859cc4ca5SDavid du Colombier if(memcmp(a, t->cmp, t->siz) < 0)
49959cc4ca5SDavid du Colombier d--;
50059cc4ca5SDavid du Colombier p = a + *na;
50159cc4ca5SDavid du Colombier *bp -= b;
50259cc4ca5SDavid du Colombier *dp += d;
50359cc4ca5SDavid du Colombier *na += d;
50459cc4ca5SDavid du Colombier mulby(a, p+d, p, b);
50559cc4ca5SDavid du Colombier }
50659cc4ca5SDavid du Colombier
50759cc4ca5SDavid du Colombier static int
xcmp(char * a,char * b)50859cc4ca5SDavid du Colombier xcmp(char *a, char *b)
50959cc4ca5SDavid du Colombier {
51059cc4ca5SDavid du Colombier int c1, c2;
51159cc4ca5SDavid du Colombier
51259cc4ca5SDavid du Colombier while(c1 = *b++) {
51359cc4ca5SDavid du Colombier c2 = *a++;
51459cc4ca5SDavid du Colombier if(isupper(c2))
51559cc4ca5SDavid du Colombier c2 = tolower(c2);
51659cc4ca5SDavid du Colombier if(c1 != c2)
51759cc4ca5SDavid du Colombier return 1;
51859cc4ca5SDavid du Colombier }
51959cc4ca5SDavid du Colombier return 0;
52059cc4ca5SDavid du Colombier }
521