18ccd4a63SDavid du Colombier #include <u.h>
28ccd4a63SDavid du Colombier #include <libc.h>
30d601874SDavid du Colombier #include "fmtdef.h"
40d601874SDavid du Colombier
50d601874SDavid du Colombier static ulong
umuldiv(ulong a,ulong b,ulong c)60d601874SDavid du Colombier umuldiv(ulong a, ulong b, ulong c)
70d601874SDavid du Colombier {
80d601874SDavid du Colombier double d;
90d601874SDavid du Colombier
100d601874SDavid du Colombier d = ((double)a * (double)b) / (double)c;
110d601874SDavid du Colombier if(d >= 4294967295.)
120d601874SDavid du Colombier d = 4294967295.;
130d601874SDavid du Colombier return (ulong)d;
140d601874SDavid du Colombier }
158ccd4a63SDavid du Colombier
168ccd4a63SDavid du Colombier /*
178ccd4a63SDavid du Colombier * This routine will convert to arbitrary precision
188ccd4a63SDavid du Colombier * floating point entirely in multi-precision fixed.
198ccd4a63SDavid du Colombier * The answer is the closest floating point number to
208ccd4a63SDavid du Colombier * the given decimal number. Exactly half way are
218ccd4a63SDavid du Colombier * rounded ala ieee rules.
228ccd4a63SDavid du Colombier * Method is to scale input decimal between .500 and .999...
238ccd4a63SDavid du Colombier * with external power of 2, then binary search for the
248ccd4a63SDavid du Colombier * closest mantissa to this decimal number.
258ccd4a63SDavid du Colombier * Nmant is is the required precision. (53 for ieee dp)
268ccd4a63SDavid du Colombier * Nbits is the max number of bits/word. (must be <= 28)
278ccd4a63SDavid du Colombier * Prec is calculated - the number of words of fixed mantissa.
288ccd4a63SDavid du Colombier */
298ccd4a63SDavid du Colombier enum
308ccd4a63SDavid du Colombier {
310d601874SDavid du Colombier Nbits = 28, /* bits safely represented in a ulong */
320d601874SDavid du Colombier Nmant = 53, /* bits of precision required */
330d601874SDavid du Colombier Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */
340d601874SDavid du Colombier Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */
358ccd4a63SDavid du Colombier Ndig = 1500,
368ccd4a63SDavid du Colombier One = (ulong)(1<<Nbits),
378ccd4a63SDavid du Colombier Half = (ulong)(One>>1),
388ccd4a63SDavid du Colombier Maxe = 310,
398ccd4a63SDavid du Colombier
400d601874SDavid du Colombier Fsign = 1<<0, /* found - */
410d601874SDavid du Colombier Fesign = 1<<1, /* found e- */
420d601874SDavid du Colombier Fdpoint = 1<<2, /* found . */
430d601874SDavid du Colombier
440d601874SDavid du Colombier S0 = 0, /* _ _S0 +S1 #S2 .S3 */
450d601874SDavid du Colombier S1, /* _+ #S2 .S3 */
460d601874SDavid du Colombier S2, /* _+# #S2 .S4 eS5 */
470d601874SDavid du Colombier S3, /* _+. #S4 */
480d601874SDavid du Colombier S4, /* _+#.# #S4 eS5 */
490d601874SDavid du Colombier S5, /* _+#.#e +S6 #S7 */
500d601874SDavid du Colombier S6, /* _+#.#e+ #S7 */
510d601874SDavid du Colombier S7, /* _+#.#e+# #S7 */
528ccd4a63SDavid du Colombier };
538ccd4a63SDavid du Colombier
548ccd4a63SDavid du Colombier static int xcmp(char*, char*);
558ccd4a63SDavid du Colombier static int fpcmp(char*, ulong*);
568ccd4a63SDavid du Colombier static void frnorm(ulong*);
578ccd4a63SDavid du Colombier static void divascii(char*, int*, int*, int*);
588ccd4a63SDavid du Colombier static void mulascii(char*, int*, int*, int*);
598ccd4a63SDavid du Colombier
608ccd4a63SDavid du Colombier typedef struct Tab Tab;
618ccd4a63SDavid du Colombier struct Tab
628ccd4a63SDavid du Colombier {
638ccd4a63SDavid du Colombier int bp;
648ccd4a63SDavid du Colombier int siz;
658ccd4a63SDavid du Colombier char* cmp;
668ccd4a63SDavid du Colombier };
678ccd4a63SDavid du Colombier
689cd23d14SDavid du Colombier #ifndef ERANGE
699cd23d14SDavid du Colombier #define ERANGE 12345
709cd23d14SDavid du Colombier #endif
719cd23d14SDavid du Colombier
728ccd4a63SDavid du Colombier double
fmtstrtod(const char * as,char ** aas)730d601874SDavid du Colombier fmtstrtod(const char *as, char **aas)
748ccd4a63SDavid du Colombier {
750d601874SDavid du Colombier int na, ex, dp, bp, c, i, flag, state;
760d601874SDavid du Colombier ulong low[Prec], hig[Prec], mid[Prec];
778ccd4a63SDavid du Colombier double d;
788ccd4a63SDavid du Colombier char *s, a[Ndig];
798ccd4a63SDavid du Colombier
800d601874SDavid du Colombier flag = 0; /* Fsign, Fesign, Fdpoint */
810d601874SDavid du Colombier na = 0; /* number of digits of a[] */
820d601874SDavid du Colombier dp = 0; /* na of decimal point */
830d601874SDavid du Colombier ex = 0; /* exonent */
848ccd4a63SDavid du Colombier
858ccd4a63SDavid du Colombier state = S0;
860d601874SDavid du Colombier for(s=(char*)as;; s++) {
878ccd4a63SDavid du Colombier c = *s;
888ccd4a63SDavid du Colombier if(c >= '0' && c <= '9') {
898ccd4a63SDavid du Colombier switch(state) {
908ccd4a63SDavid du Colombier case S0:
918ccd4a63SDavid du Colombier case S1:
928ccd4a63SDavid du Colombier case S2:
938ccd4a63SDavid du Colombier state = S2;
948ccd4a63SDavid du Colombier break;
958ccd4a63SDavid du Colombier case S3:
968ccd4a63SDavid du Colombier case S4:
978ccd4a63SDavid du Colombier state = S4;
988ccd4a63SDavid du Colombier break;
998ccd4a63SDavid du Colombier
1008ccd4a63SDavid du Colombier case S5:
1018ccd4a63SDavid du Colombier case S6:
1028ccd4a63SDavid du Colombier case S7:
1038ccd4a63SDavid du Colombier state = S7;
1048ccd4a63SDavid du Colombier ex = ex*10 + (c-'0');
1058ccd4a63SDavid du Colombier continue;
1068ccd4a63SDavid du Colombier }
1078ccd4a63SDavid du Colombier if(na == 0 && c == '0') {
1088ccd4a63SDavid du Colombier dp--;
1098ccd4a63SDavid du Colombier continue;
1108ccd4a63SDavid du Colombier }
1118ccd4a63SDavid du Colombier if(na < Ndig-50)
1128ccd4a63SDavid du Colombier a[na++] = c;
1138ccd4a63SDavid du Colombier continue;
1148ccd4a63SDavid du Colombier }
1158ccd4a63SDavid du Colombier switch(c) {
1168ccd4a63SDavid du Colombier case '\t':
1178ccd4a63SDavid du Colombier case '\n':
1188ccd4a63SDavid du Colombier case '\v':
1198ccd4a63SDavid du Colombier case '\f':
1208ccd4a63SDavid du Colombier case '\r':
1218ccd4a63SDavid du Colombier case ' ':
1228ccd4a63SDavid du Colombier if(state == S0)
1238ccd4a63SDavid du Colombier continue;
1248ccd4a63SDavid du Colombier break;
1258ccd4a63SDavid du Colombier case '-':
1268ccd4a63SDavid du Colombier if(state == S0)
1278ccd4a63SDavid du Colombier flag |= Fsign;
1288ccd4a63SDavid du Colombier else
1298ccd4a63SDavid du Colombier flag |= Fesign;
1308ccd4a63SDavid du Colombier case '+':
1318ccd4a63SDavid du Colombier if(state == S0)
1328ccd4a63SDavid du Colombier state = S1;
1338ccd4a63SDavid du Colombier else
1348ccd4a63SDavid du Colombier if(state == S5)
1358ccd4a63SDavid du Colombier state = S6;
1368ccd4a63SDavid du Colombier else
1370d601874SDavid du Colombier break; /* syntax */
1388ccd4a63SDavid du Colombier continue;
1398ccd4a63SDavid du Colombier case '.':
1408ccd4a63SDavid du Colombier flag |= Fdpoint;
1418ccd4a63SDavid du Colombier dp = na;
1428ccd4a63SDavid du Colombier if(state == S0 || state == S1) {
1438ccd4a63SDavid du Colombier state = S3;
1448ccd4a63SDavid du Colombier continue;
1458ccd4a63SDavid du Colombier }
1468ccd4a63SDavid du Colombier if(state == S2) {
1478ccd4a63SDavid du Colombier state = S4;
1488ccd4a63SDavid du Colombier continue;
1498ccd4a63SDavid du Colombier }
1508ccd4a63SDavid du Colombier break;
1518ccd4a63SDavid du Colombier case 'e':
1528ccd4a63SDavid du Colombier case 'E':
1538ccd4a63SDavid du Colombier if(state == S2 || state == S4) {
1548ccd4a63SDavid du Colombier state = S5;
1558ccd4a63SDavid du Colombier continue;
1568ccd4a63SDavid du Colombier }
1578ccd4a63SDavid du Colombier break;
1588ccd4a63SDavid du Colombier }
1598ccd4a63SDavid du Colombier break;
1608ccd4a63SDavid du Colombier }
1618ccd4a63SDavid du Colombier
1628ccd4a63SDavid du Colombier /*
1638ccd4a63SDavid du Colombier * clean up return char-pointer
1648ccd4a63SDavid du Colombier */
1658ccd4a63SDavid du Colombier switch(state) {
1668ccd4a63SDavid du Colombier case S0:
1678ccd4a63SDavid du Colombier if(xcmp(s, "nan") == 0) {
1688ccd4a63SDavid du Colombier if(aas != nil)
1698ccd4a63SDavid du Colombier *aas = s+3;
1708ccd4a63SDavid du Colombier goto retnan;
1718ccd4a63SDavid du Colombier }
1728ccd4a63SDavid du Colombier case S1:
1738ccd4a63SDavid du Colombier if(xcmp(s, "infinity") == 0) {
1748ccd4a63SDavid du Colombier if(aas != nil)
1758ccd4a63SDavid du Colombier *aas = s+8;
1768ccd4a63SDavid du Colombier goto retinf;
1778ccd4a63SDavid du Colombier }
1788ccd4a63SDavid du Colombier if(xcmp(s, "inf") == 0) {
1798ccd4a63SDavid du Colombier if(aas != nil)
1808ccd4a63SDavid du Colombier *aas = s+3;
1818ccd4a63SDavid du Colombier goto retinf;
1828ccd4a63SDavid du Colombier }
1838ccd4a63SDavid du Colombier case S3:
1848ccd4a63SDavid du Colombier if(aas != nil)
1850d601874SDavid du Colombier *aas = (char*)as;
1860d601874SDavid du Colombier goto ret0; /* no digits found */
1878ccd4a63SDavid du Colombier case S6:
1880d601874SDavid du Colombier s--; /* back over +- */
1898ccd4a63SDavid du Colombier case S5:
1900d601874SDavid du Colombier s--; /* back over e */
1918ccd4a63SDavid du Colombier break;
1928ccd4a63SDavid du Colombier }
1938ccd4a63SDavid du Colombier if(aas != nil)
1948ccd4a63SDavid du Colombier *aas = s;
1958ccd4a63SDavid du Colombier
1968ccd4a63SDavid du Colombier if(flag & Fdpoint)
1978ccd4a63SDavid du Colombier while(na > 0 && a[na-1] == '0')
1988ccd4a63SDavid du Colombier na--;
1998ccd4a63SDavid du Colombier if(na == 0)
2000d601874SDavid du Colombier goto ret0; /* zero */
2018ccd4a63SDavid du Colombier a[na] = 0;
2028ccd4a63SDavid du Colombier if(!(flag & Fdpoint))
2038ccd4a63SDavid du Colombier dp = na;
2048ccd4a63SDavid du Colombier if(flag & Fesign)
2058ccd4a63SDavid du Colombier ex = -ex;
2068ccd4a63SDavid du Colombier dp += ex;
2070d601874SDavid du Colombier if(dp < -Maxe){
2080d601874SDavid du Colombier errno = ERANGE;
2090d601874SDavid du Colombier goto ret0; /* underflow by exp */
2100d601874SDavid du Colombier } else
2118ccd4a63SDavid du Colombier if(dp > +Maxe)
2120d601874SDavid du Colombier goto retinf; /* overflow by exp */
2138ccd4a63SDavid du Colombier
2148ccd4a63SDavid du Colombier /*
2158ccd4a63SDavid du Colombier * normalize the decimal ascii number
2168ccd4a63SDavid du Colombier * to range .[5-9][0-9]* e0
2178ccd4a63SDavid du Colombier */
2180d601874SDavid du Colombier bp = 0; /* binary exponent */
2198ccd4a63SDavid du Colombier while(dp > 0)
2208ccd4a63SDavid du Colombier divascii(a, &na, &dp, &bp);
2218ccd4a63SDavid du Colombier while(dp < 0 || a[0] < '5')
2228ccd4a63SDavid du Colombier mulascii(a, &na, &dp, &bp);
2238ccd4a63SDavid du Colombier
2248ccd4a63SDavid du Colombier /* close approx by naive conversion */
2250d601874SDavid du Colombier mid[0] = 0;
2260d601874SDavid du Colombier mid[1] = 1;
227*ec59a3ddSDavid du Colombier for(i=0; (c=a[i]); i++) {
2280d601874SDavid du Colombier mid[0] = mid[0]*10 + (c-'0');
2290d601874SDavid du Colombier mid[1] = mid[1]*10;
2300d601874SDavid du Colombier if(i >= 8)
2310d601874SDavid du Colombier break;
2328ccd4a63SDavid du Colombier }
2330d601874SDavid du Colombier low[0] = umuldiv(mid[0], One, mid[1]);
2340d601874SDavid du Colombier hig[0] = umuldiv(mid[0]+1, One, mid[1]);
2358ccd4a63SDavid du Colombier for(i=1; i<Prec; i++) {
2368ccd4a63SDavid du Colombier low[i] = 0;
2378ccd4a63SDavid du Colombier hig[i] = One-1;
2388ccd4a63SDavid du Colombier }
2398ccd4a63SDavid du Colombier
2408ccd4a63SDavid du Colombier /* binary search for closest mantissa */
2418ccd4a63SDavid du Colombier for(;;) {
2428ccd4a63SDavid du Colombier /* mid = (hig + low) / 2 */
2438ccd4a63SDavid du Colombier c = 0;
2448ccd4a63SDavid du Colombier for(i=0; i<Prec; i++) {
2458ccd4a63SDavid du Colombier mid[i] = hig[i] + low[i];
2468ccd4a63SDavid du Colombier if(c)
2478ccd4a63SDavid du Colombier mid[i] += One;
2488ccd4a63SDavid du Colombier c = mid[i] & 1;
2498ccd4a63SDavid du Colombier mid[i] >>= 1;
2508ccd4a63SDavid du Colombier }
2518ccd4a63SDavid du Colombier frnorm(mid);
2528ccd4a63SDavid du Colombier
2538ccd4a63SDavid du Colombier /* compare */
2548ccd4a63SDavid du Colombier c = fpcmp(a, mid);
2558ccd4a63SDavid du Colombier if(c > 0) {
2568ccd4a63SDavid du Colombier c = 1;
2578ccd4a63SDavid du Colombier for(i=0; i<Prec; i++)
2588ccd4a63SDavid du Colombier if(low[i] != mid[i]) {
2598ccd4a63SDavid du Colombier c = 0;
2608ccd4a63SDavid du Colombier low[i] = mid[i];
2618ccd4a63SDavid du Colombier }
2628ccd4a63SDavid du Colombier if(c)
2630d601874SDavid du Colombier break; /* between mid and hig */
2648ccd4a63SDavid du Colombier continue;
2658ccd4a63SDavid du Colombier }
2668ccd4a63SDavid du Colombier if(c < 0) {
2678ccd4a63SDavid du Colombier for(i=0; i<Prec; i++)
2688ccd4a63SDavid du Colombier hig[i] = mid[i];
2698ccd4a63SDavid du Colombier continue;
2708ccd4a63SDavid du Colombier }
2718ccd4a63SDavid du Colombier
2728ccd4a63SDavid du Colombier /* only hard part is if even/odd roundings wants to go up */
2738ccd4a63SDavid du Colombier c = mid[Prec-1] & (Sigbit-1);
2748ccd4a63SDavid du Colombier if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
2758ccd4a63SDavid du Colombier mid[Prec-1] -= c;
2760d601874SDavid du Colombier break; /* exactly mid */
2778ccd4a63SDavid du Colombier }
2788ccd4a63SDavid du Colombier
2798ccd4a63SDavid du Colombier /* normal rounding applies */
2808ccd4a63SDavid du Colombier c = mid[Prec-1] & (Sigbit-1);
2818ccd4a63SDavid du Colombier mid[Prec-1] -= c;
2828ccd4a63SDavid du Colombier if(c >= Sigbit/2) {
2838ccd4a63SDavid du Colombier mid[Prec-1] += Sigbit;
2848ccd4a63SDavid du Colombier frnorm(mid);
2858ccd4a63SDavid du Colombier }
2860d601874SDavid du Colombier goto out;
2878ccd4a63SDavid du Colombier
2888ccd4a63SDavid du Colombier ret0:
2898ccd4a63SDavid du Colombier return 0;
2908ccd4a63SDavid du Colombier
2918ccd4a63SDavid du Colombier retnan:
2928ccd4a63SDavid du Colombier return __NaN();
2938ccd4a63SDavid du Colombier
2948ccd4a63SDavid du Colombier retinf:
2950d601874SDavid du Colombier /*
2960d601874SDavid du Colombier * Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */
2970d601874SDavid du Colombier errno = ERANGE;
2988ccd4a63SDavid du Colombier if(flag & Fsign)
2990d601874SDavid du Colombier return -HUGE_VAL;
3000d601874SDavid du Colombier return HUGE_VAL;
3010d601874SDavid du Colombier
3020d601874SDavid du Colombier out:
3030d601874SDavid du Colombier d = 0;
3040d601874SDavid du Colombier for(i=0; i<Prec; i++)
3050d601874SDavid du Colombier d = d*One + mid[i];
3060d601874SDavid du Colombier if(flag & Fsign)
3070d601874SDavid du Colombier d = -d;
3080d601874SDavid du Colombier d = ldexp(d, bp - Prec*Nbits);
3090d601874SDavid du Colombier if(d == 0){ /* underflow */
3100d601874SDavid du Colombier errno = ERANGE;
3110d601874SDavid du Colombier }
3120d601874SDavid du Colombier return d;
3138ccd4a63SDavid du Colombier }
3148ccd4a63SDavid du Colombier
3158ccd4a63SDavid du Colombier static void
frnorm(ulong * f)3168ccd4a63SDavid du Colombier frnorm(ulong *f)
3178ccd4a63SDavid du Colombier {
3188ccd4a63SDavid du Colombier int i, c;
3198ccd4a63SDavid du Colombier
3208ccd4a63SDavid du Colombier c = 0;
3218ccd4a63SDavid du Colombier for(i=Prec-1; i>0; i--) {
3228ccd4a63SDavid du Colombier f[i] += c;
3238ccd4a63SDavid du Colombier c = f[i] >> Nbits;
3248ccd4a63SDavid du Colombier f[i] &= One-1;
3258ccd4a63SDavid du Colombier }
3268ccd4a63SDavid du Colombier f[0] += c;
3278ccd4a63SDavid du Colombier }
3288ccd4a63SDavid du Colombier
3298ccd4a63SDavid du Colombier static int
fpcmp(char * a,ulong * f)3308ccd4a63SDavid du Colombier fpcmp(char *a, ulong* f)
3318ccd4a63SDavid du Colombier {
3328ccd4a63SDavid du Colombier ulong tf[Prec];
3338ccd4a63SDavid du Colombier int i, d, c;
3348ccd4a63SDavid du Colombier
3358ccd4a63SDavid du Colombier for(i=0; i<Prec; i++)
3368ccd4a63SDavid du Colombier tf[i] = f[i];
3378ccd4a63SDavid du Colombier
3388ccd4a63SDavid du Colombier for(;;) {
3398ccd4a63SDavid du Colombier /* tf *= 10 */
3408ccd4a63SDavid du Colombier for(i=0; i<Prec; i++)
3418ccd4a63SDavid du Colombier tf[i] = tf[i]*10;
3428ccd4a63SDavid du Colombier frnorm(tf);
3438ccd4a63SDavid du Colombier d = (tf[0] >> Nbits) + '0';
3448ccd4a63SDavid du Colombier tf[0] &= One-1;
3458ccd4a63SDavid du Colombier
3468ccd4a63SDavid du Colombier /* compare next digit */
3478ccd4a63SDavid du Colombier c = *a;
3488ccd4a63SDavid du Colombier if(c == 0) {
3498ccd4a63SDavid du Colombier if('0' < d)
3508ccd4a63SDavid du Colombier return -1;
3518ccd4a63SDavid du Colombier if(tf[0] != 0)
3528ccd4a63SDavid du Colombier goto cont;
3538ccd4a63SDavid du Colombier for(i=1; i<Prec; i++)
3548ccd4a63SDavid du Colombier if(tf[i] != 0)
3558ccd4a63SDavid du Colombier goto cont;
3568ccd4a63SDavid du Colombier return 0;
3578ccd4a63SDavid du Colombier }
3588ccd4a63SDavid du Colombier if(c > d)
3598ccd4a63SDavid du Colombier return +1;
3608ccd4a63SDavid du Colombier if(c < d)
3618ccd4a63SDavid du Colombier return -1;
3628ccd4a63SDavid du Colombier a++;
3638ccd4a63SDavid du Colombier cont:;
3648ccd4a63SDavid du Colombier }
3658ccd4a63SDavid du Colombier }
3668ccd4a63SDavid du Colombier
3678ccd4a63SDavid du Colombier static void
divby(char * a,int * na,int b)3680d601874SDavid du Colombier divby(char *a, int *na, int b)
3698ccd4a63SDavid du Colombier {
3708ccd4a63SDavid du Colombier int n, c;
3718ccd4a63SDavid du Colombier char *p;
3728ccd4a63SDavid du Colombier
3738ccd4a63SDavid du Colombier p = a;
3748ccd4a63SDavid du Colombier n = 0;
3758ccd4a63SDavid du Colombier while(n>>b == 0) {
3768ccd4a63SDavid du Colombier c = *a++;
3778ccd4a63SDavid du Colombier if(c == 0) {
3788ccd4a63SDavid du Colombier while(n) {
3798ccd4a63SDavid du Colombier c = n*10;
3808ccd4a63SDavid du Colombier if(c>>b)
3818ccd4a63SDavid du Colombier break;
3828ccd4a63SDavid du Colombier n = c;
3838ccd4a63SDavid du Colombier }
3848ccd4a63SDavid du Colombier goto xx;
3858ccd4a63SDavid du Colombier }
3868ccd4a63SDavid du Colombier n = n*10 + c-'0';
3878ccd4a63SDavid du Colombier (*na)--;
3888ccd4a63SDavid du Colombier }
3898ccd4a63SDavid du Colombier for(;;) {
3908ccd4a63SDavid du Colombier c = n>>b;
3918ccd4a63SDavid du Colombier n -= c<<b;
3928ccd4a63SDavid du Colombier *p++ = c + '0';
3938ccd4a63SDavid du Colombier c = *a++;
3948ccd4a63SDavid du Colombier if(c == 0)
3958ccd4a63SDavid du Colombier break;
3968ccd4a63SDavid du Colombier n = n*10 + c-'0';
3978ccd4a63SDavid du Colombier }
3988ccd4a63SDavid du Colombier (*na)++;
3998ccd4a63SDavid du Colombier xx:
4008ccd4a63SDavid du Colombier while(n) {
4018ccd4a63SDavid du Colombier n = n*10;
4028ccd4a63SDavid du Colombier c = n>>b;
4038ccd4a63SDavid du Colombier n -= c<<b;
4048ccd4a63SDavid du Colombier *p++ = c + '0';
4058ccd4a63SDavid du Colombier (*na)++;
4068ccd4a63SDavid du Colombier }
4078ccd4a63SDavid du Colombier *p = 0;
4088ccd4a63SDavid du Colombier }
4098ccd4a63SDavid du Colombier
4108ccd4a63SDavid du Colombier static Tab tab1[] =
4118ccd4a63SDavid du Colombier {
4128ccd4a63SDavid du Colombier 1, 0, "",
4138ccd4a63SDavid du Colombier 3, 1, "7",
4148ccd4a63SDavid du Colombier 6, 2, "63",
4158ccd4a63SDavid du Colombier 9, 3, "511",
4168ccd4a63SDavid du Colombier 13, 4, "8191",
4178ccd4a63SDavid du Colombier 16, 5, "65535",
4188ccd4a63SDavid du Colombier 19, 6, "524287",
4198ccd4a63SDavid du Colombier 23, 7, "8388607",
4208ccd4a63SDavid du Colombier 26, 8, "67108863",
4218ccd4a63SDavid du Colombier 27, 9, "134217727",
4228ccd4a63SDavid du Colombier };
4238ccd4a63SDavid du Colombier
4248ccd4a63SDavid du Colombier static void
divascii(char * a,int * na,int * dp,int * bp)4258ccd4a63SDavid du Colombier divascii(char *a, int *na, int *dp, int *bp)
4268ccd4a63SDavid du Colombier {
4278ccd4a63SDavid du Colombier int b, d;
4288ccd4a63SDavid du Colombier Tab *t;
4298ccd4a63SDavid du Colombier
4308ccd4a63SDavid du Colombier d = *dp;
4310d601874SDavid du Colombier if(d >= (int)(nelem(tab1)))
4320d601874SDavid du Colombier d = (int)(nelem(tab1))-1;
4338ccd4a63SDavid du Colombier t = tab1 + d;
4348ccd4a63SDavid du Colombier b = t->bp;
4358ccd4a63SDavid du Colombier if(memcmp(a, t->cmp, t->siz) > 0)
4368ccd4a63SDavid du Colombier d--;
4378ccd4a63SDavid du Colombier *dp -= d;
4388ccd4a63SDavid du Colombier *bp += b;
4398ccd4a63SDavid du Colombier divby(a, na, b);
4408ccd4a63SDavid du Colombier }
4418ccd4a63SDavid du Colombier
4428ccd4a63SDavid du Colombier static void
mulby(char * a,char * p,char * q,int b)4438ccd4a63SDavid du Colombier mulby(char *a, char *p, char *q, int b)
4448ccd4a63SDavid du Colombier {
4458ccd4a63SDavid du Colombier int n, c;
4468ccd4a63SDavid du Colombier
4478ccd4a63SDavid du Colombier n = 0;
4488ccd4a63SDavid du Colombier *p = 0;
4498ccd4a63SDavid du Colombier for(;;) {
4508ccd4a63SDavid du Colombier q--;
4518ccd4a63SDavid du Colombier if(q < a)
4528ccd4a63SDavid du Colombier break;
4538ccd4a63SDavid du Colombier c = *q - '0';
4548ccd4a63SDavid du Colombier c = (c<<b) + n;
4558ccd4a63SDavid du Colombier n = c/10;
4568ccd4a63SDavid du Colombier c -= n*10;
4578ccd4a63SDavid du Colombier p--;
4588ccd4a63SDavid du Colombier *p = c + '0';
4598ccd4a63SDavid du Colombier }
4608ccd4a63SDavid du Colombier while(n) {
4618ccd4a63SDavid du Colombier c = n;
4628ccd4a63SDavid du Colombier n = c/10;
4638ccd4a63SDavid du Colombier c -= n*10;
4648ccd4a63SDavid du Colombier p--;
4658ccd4a63SDavid du Colombier *p = c + '0';
4668ccd4a63SDavid du Colombier }
4678ccd4a63SDavid du Colombier }
4688ccd4a63SDavid du Colombier
4698ccd4a63SDavid du Colombier static Tab tab2[] =
4708ccd4a63SDavid du Colombier {
4710d601874SDavid du Colombier 1, 1, "", /* dp = 0-0 */
4728ccd4a63SDavid du Colombier 3, 3, "125",
4738ccd4a63SDavid du Colombier 6, 5, "15625",
4748ccd4a63SDavid du Colombier 9, 7, "1953125",
4758ccd4a63SDavid du Colombier 13, 10, "1220703125",
4768ccd4a63SDavid du Colombier 16, 12, "152587890625",
4778ccd4a63SDavid du Colombier 19, 14, "19073486328125",
4788ccd4a63SDavid du Colombier 23, 17, "11920928955078125",
4798ccd4a63SDavid du Colombier 26, 19, "1490116119384765625",
4800d601874SDavid du Colombier 27, 19, "7450580596923828125", /* dp 8-9 */
4818ccd4a63SDavid du Colombier };
4828ccd4a63SDavid du Colombier
4838ccd4a63SDavid du Colombier static void
mulascii(char * a,int * na,int * dp,int * bp)4848ccd4a63SDavid du Colombier mulascii(char *a, int *na, int *dp, int *bp)
4858ccd4a63SDavid du Colombier {
4868ccd4a63SDavid du Colombier char *p;
4878ccd4a63SDavid du Colombier int d, b;
4888ccd4a63SDavid du Colombier Tab *t;
4898ccd4a63SDavid du Colombier
4908ccd4a63SDavid du Colombier d = -*dp;
4910d601874SDavid du Colombier if(d >= (int)(nelem(tab2)))
4920d601874SDavid du Colombier d = (int)(nelem(tab2))-1;
4938ccd4a63SDavid du Colombier t = tab2 + d;
4948ccd4a63SDavid du Colombier b = t->bp;
4958ccd4a63SDavid du Colombier if(memcmp(a, t->cmp, t->siz) < 0)
4968ccd4a63SDavid du Colombier d--;
4978ccd4a63SDavid du Colombier p = a + *na;
4988ccd4a63SDavid du Colombier *bp -= b;
4998ccd4a63SDavid du Colombier *dp += d;
5008ccd4a63SDavid du Colombier *na += d;
5018ccd4a63SDavid du Colombier mulby(a, p+d, p, b);
5028ccd4a63SDavid du Colombier }
5038ccd4a63SDavid du Colombier
5048ccd4a63SDavid du Colombier static int
xcmp(char * a,char * b)5058ccd4a63SDavid du Colombier xcmp(char *a, char *b)
5068ccd4a63SDavid du Colombier {
5078ccd4a63SDavid du Colombier int c1, c2;
5088ccd4a63SDavid du Colombier
5098ccd4a63SDavid du Colombier while((c1 = *b++)) {
5108ccd4a63SDavid du Colombier c2 = *a++;
5118ccd4a63SDavid du Colombier if(isupper(c2))
5128ccd4a63SDavid du Colombier c2 = tolower(c2);
5138ccd4a63SDavid du Colombier if(c1 != c2)
5148ccd4a63SDavid du Colombier return 1;
5158ccd4a63SDavid du Colombier }
5168ccd4a63SDavid du Colombier return 0;
5178ccd4a63SDavid du Colombier }
518