1*0d601874SDavid du Colombier /* 2*0d601874SDavid du Colombier * The authors of this software are Rob Pike and Ken Thompson. 3*0d601874SDavid du Colombier * Copyright (c) 2002 by Lucent Technologies. 4*0d601874SDavid du Colombier * Permission to use, copy, modify, and distribute this software for any 5*0d601874SDavid du Colombier * purpose without fee is hereby granted, provided that this entire notice 6*0d601874SDavid du Colombier * is included in all copies of any software which is or includes a copy 7*0d601874SDavid du Colombier * or modification of this software and in all copies of the supporting 8*0d601874SDavid du Colombier * documentation for such software. 9*0d601874SDavid du Colombier * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 10*0d601874SDavid du Colombier * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE 11*0d601874SDavid du Colombier * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 12*0d601874SDavid du Colombier * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 13*0d601874SDavid du Colombier */ 148ccd4a63SDavid du Colombier #include <u.h> 158ccd4a63SDavid du Colombier #include <libc.h> 16*0d601874SDavid du Colombier #include "fmtdef.h" 17*0d601874SDavid du Colombier 18*0d601874SDavid du Colombier static ulong 19*0d601874SDavid du Colombier umuldiv(ulong a, ulong b, ulong c) 20*0d601874SDavid du Colombier { 21*0d601874SDavid du Colombier double d; 22*0d601874SDavid du Colombier 23*0d601874SDavid du Colombier d = ((double)a * (double)b) / (double)c; 24*0d601874SDavid du Colombier if(d >= 4294967295.) 25*0d601874SDavid du Colombier d = 4294967295.; 26*0d601874SDavid du Colombier return (ulong)d; 27*0d601874SDavid du Colombier } 288ccd4a63SDavid du Colombier 298ccd4a63SDavid du Colombier /* 308ccd4a63SDavid du Colombier * This routine will convert to arbitrary precision 318ccd4a63SDavid du Colombier * floating point entirely in multi-precision fixed. 328ccd4a63SDavid du Colombier * The answer is the closest floating point number to 338ccd4a63SDavid du Colombier * the given decimal number. Exactly half way are 348ccd4a63SDavid du Colombier * rounded ala ieee rules. 358ccd4a63SDavid du Colombier * Method is to scale input decimal between .500 and .999... 368ccd4a63SDavid du Colombier * with external power of 2, then binary search for the 378ccd4a63SDavid du Colombier * closest mantissa to this decimal number. 388ccd4a63SDavid du Colombier * Nmant is is the required precision. (53 for ieee dp) 398ccd4a63SDavid du Colombier * Nbits is the max number of bits/word. (must be <= 28) 408ccd4a63SDavid du Colombier * Prec is calculated - the number of words of fixed mantissa. 418ccd4a63SDavid du Colombier */ 428ccd4a63SDavid du Colombier enum 438ccd4a63SDavid du Colombier { 44*0d601874SDavid du Colombier Nbits = 28, /* bits safely represented in a ulong */ 45*0d601874SDavid du Colombier Nmant = 53, /* bits of precision required */ 46*0d601874SDavid du Colombier Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */ 47*0d601874SDavid du Colombier Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */ 488ccd4a63SDavid du Colombier Ndig = 1500, 498ccd4a63SDavid du Colombier One = (ulong)(1<<Nbits), 508ccd4a63SDavid du Colombier Half = (ulong)(One>>1), 518ccd4a63SDavid du Colombier Maxe = 310, 528ccd4a63SDavid du Colombier 53*0d601874SDavid du Colombier Fsign = 1<<0, /* found - */ 54*0d601874SDavid du Colombier Fesign = 1<<1, /* found e- */ 55*0d601874SDavid du Colombier Fdpoint = 1<<2, /* found . */ 56*0d601874SDavid du Colombier 57*0d601874SDavid du Colombier S0 = 0, /* _ _S0 +S1 #S2 .S3 */ 58*0d601874SDavid du Colombier S1, /* _+ #S2 .S3 */ 59*0d601874SDavid du Colombier S2, /* _+# #S2 .S4 eS5 */ 60*0d601874SDavid du Colombier S3, /* _+. #S4 */ 61*0d601874SDavid du Colombier S4, /* _+#.# #S4 eS5 */ 62*0d601874SDavid du Colombier S5, /* _+#.#e +S6 #S7 */ 63*0d601874SDavid du Colombier S6, /* _+#.#e+ #S7 */ 64*0d601874SDavid du Colombier S7, /* _+#.#e+# #S7 */ 658ccd4a63SDavid du Colombier }; 668ccd4a63SDavid du Colombier 678ccd4a63SDavid du Colombier static int xcmp(char*, char*); 688ccd4a63SDavid du Colombier static int fpcmp(char*, ulong*); 698ccd4a63SDavid du Colombier static void frnorm(ulong*); 708ccd4a63SDavid du Colombier static void divascii(char*, int*, int*, int*); 718ccd4a63SDavid du Colombier static void mulascii(char*, int*, int*, int*); 728ccd4a63SDavid du Colombier 738ccd4a63SDavid du Colombier typedef struct Tab Tab; 748ccd4a63SDavid du Colombier struct Tab 758ccd4a63SDavid du Colombier { 768ccd4a63SDavid du Colombier int bp; 778ccd4a63SDavid du Colombier int siz; 788ccd4a63SDavid du Colombier char* cmp; 798ccd4a63SDavid du Colombier }; 808ccd4a63SDavid du Colombier 818ccd4a63SDavid du Colombier double 82*0d601874SDavid du Colombier fmtstrtod(const char *as, char **aas) 838ccd4a63SDavid du Colombier { 84*0d601874SDavid du Colombier int na, ex, dp, bp, c, i, flag, state; 85*0d601874SDavid du Colombier ulong low[Prec], hig[Prec], mid[Prec]; 868ccd4a63SDavid du Colombier double d; 878ccd4a63SDavid du Colombier char *s, a[Ndig]; 888ccd4a63SDavid du Colombier 89*0d601874SDavid du Colombier flag = 0; /* Fsign, Fesign, Fdpoint */ 90*0d601874SDavid du Colombier na = 0; /* number of digits of a[] */ 91*0d601874SDavid du Colombier dp = 0; /* na of decimal point */ 92*0d601874SDavid du Colombier ex = 0; /* exonent */ 938ccd4a63SDavid du Colombier 948ccd4a63SDavid du Colombier state = S0; 95*0d601874SDavid du Colombier for(s=(char*)as;; s++) { 968ccd4a63SDavid du Colombier c = *s; 978ccd4a63SDavid du Colombier if(c >= '0' && c <= '9') { 988ccd4a63SDavid du Colombier switch(state) { 998ccd4a63SDavid du Colombier case S0: 1008ccd4a63SDavid du Colombier case S1: 1018ccd4a63SDavid du Colombier case S2: 1028ccd4a63SDavid du Colombier state = S2; 1038ccd4a63SDavid du Colombier break; 1048ccd4a63SDavid du Colombier case S3: 1058ccd4a63SDavid du Colombier case S4: 1068ccd4a63SDavid du Colombier state = S4; 1078ccd4a63SDavid du Colombier break; 1088ccd4a63SDavid du Colombier 1098ccd4a63SDavid du Colombier case S5: 1108ccd4a63SDavid du Colombier case S6: 1118ccd4a63SDavid du Colombier case S7: 1128ccd4a63SDavid du Colombier state = S7; 1138ccd4a63SDavid du Colombier ex = ex*10 + (c-'0'); 1148ccd4a63SDavid du Colombier continue; 1158ccd4a63SDavid du Colombier } 1168ccd4a63SDavid du Colombier if(na == 0 && c == '0') { 1178ccd4a63SDavid du Colombier dp--; 1188ccd4a63SDavid du Colombier continue; 1198ccd4a63SDavid du Colombier } 1208ccd4a63SDavid du Colombier if(na < Ndig-50) 1218ccd4a63SDavid du Colombier a[na++] = c; 1228ccd4a63SDavid du Colombier continue; 1238ccd4a63SDavid du Colombier } 1248ccd4a63SDavid du Colombier switch(c) { 1258ccd4a63SDavid du Colombier case '\t': 1268ccd4a63SDavid du Colombier case '\n': 1278ccd4a63SDavid du Colombier case '\v': 1288ccd4a63SDavid du Colombier case '\f': 1298ccd4a63SDavid du Colombier case '\r': 1308ccd4a63SDavid du Colombier case ' ': 1318ccd4a63SDavid du Colombier if(state == S0) 1328ccd4a63SDavid du Colombier continue; 1338ccd4a63SDavid du Colombier break; 1348ccd4a63SDavid du Colombier case '-': 1358ccd4a63SDavid du Colombier if(state == S0) 1368ccd4a63SDavid du Colombier flag |= Fsign; 1378ccd4a63SDavid du Colombier else 1388ccd4a63SDavid du Colombier flag |= Fesign; 1398ccd4a63SDavid du Colombier case '+': 1408ccd4a63SDavid du Colombier if(state == S0) 1418ccd4a63SDavid du Colombier state = S1; 1428ccd4a63SDavid du Colombier else 1438ccd4a63SDavid du Colombier if(state == S5) 1448ccd4a63SDavid du Colombier state = S6; 1458ccd4a63SDavid du Colombier else 146*0d601874SDavid du Colombier break; /* syntax */ 1478ccd4a63SDavid du Colombier continue; 1488ccd4a63SDavid du Colombier case '.': 1498ccd4a63SDavid du Colombier flag |= Fdpoint; 1508ccd4a63SDavid du Colombier dp = na; 1518ccd4a63SDavid du Colombier if(state == S0 || state == S1) { 1528ccd4a63SDavid du Colombier state = S3; 1538ccd4a63SDavid du Colombier continue; 1548ccd4a63SDavid du Colombier } 1558ccd4a63SDavid du Colombier if(state == S2) { 1568ccd4a63SDavid du Colombier state = S4; 1578ccd4a63SDavid du Colombier continue; 1588ccd4a63SDavid du Colombier } 1598ccd4a63SDavid du Colombier break; 1608ccd4a63SDavid du Colombier case 'e': 1618ccd4a63SDavid du Colombier case 'E': 1628ccd4a63SDavid du Colombier if(state == S2 || state == S4) { 1638ccd4a63SDavid du Colombier state = S5; 1648ccd4a63SDavid du Colombier continue; 1658ccd4a63SDavid du Colombier } 1668ccd4a63SDavid du Colombier break; 1678ccd4a63SDavid du Colombier } 1688ccd4a63SDavid du Colombier break; 1698ccd4a63SDavid du Colombier } 1708ccd4a63SDavid du Colombier 1718ccd4a63SDavid du Colombier /* 1728ccd4a63SDavid du Colombier * clean up return char-pointer 1738ccd4a63SDavid du Colombier */ 1748ccd4a63SDavid du Colombier switch(state) { 1758ccd4a63SDavid du Colombier case S0: 1768ccd4a63SDavid du Colombier if(xcmp(s, "nan") == 0) { 1778ccd4a63SDavid du Colombier if(aas != nil) 1788ccd4a63SDavid du Colombier *aas = s+3; 1798ccd4a63SDavid du Colombier goto retnan; 1808ccd4a63SDavid du Colombier } 1818ccd4a63SDavid du Colombier case S1: 1828ccd4a63SDavid du Colombier if(xcmp(s, "infinity") == 0) { 1838ccd4a63SDavid du Colombier if(aas != nil) 1848ccd4a63SDavid du Colombier *aas = s+8; 1858ccd4a63SDavid du Colombier goto retinf; 1868ccd4a63SDavid du Colombier } 1878ccd4a63SDavid du Colombier if(xcmp(s, "inf") == 0) { 1888ccd4a63SDavid du Colombier if(aas != nil) 1898ccd4a63SDavid du Colombier *aas = s+3; 1908ccd4a63SDavid du Colombier goto retinf; 1918ccd4a63SDavid du Colombier } 1928ccd4a63SDavid du Colombier case S3: 1938ccd4a63SDavid du Colombier if(aas != nil) 194*0d601874SDavid du Colombier *aas = (char*)as; 195*0d601874SDavid du Colombier goto ret0; /* no digits found */ 1968ccd4a63SDavid du Colombier case S6: 197*0d601874SDavid du Colombier s--; /* back over +- */ 1988ccd4a63SDavid du Colombier case S5: 199*0d601874SDavid du Colombier s--; /* back over e */ 2008ccd4a63SDavid du Colombier break; 2018ccd4a63SDavid du Colombier } 2028ccd4a63SDavid du Colombier if(aas != nil) 2038ccd4a63SDavid du Colombier *aas = s; 2048ccd4a63SDavid du Colombier 2058ccd4a63SDavid du Colombier if(flag & Fdpoint) 2068ccd4a63SDavid du Colombier while(na > 0 && a[na-1] == '0') 2078ccd4a63SDavid du Colombier na--; 2088ccd4a63SDavid du Colombier if(na == 0) 209*0d601874SDavid du Colombier goto ret0; /* zero */ 2108ccd4a63SDavid du Colombier a[na] = 0; 2118ccd4a63SDavid du Colombier if(!(flag & Fdpoint)) 2128ccd4a63SDavid du Colombier dp = na; 2138ccd4a63SDavid du Colombier if(flag & Fesign) 2148ccd4a63SDavid du Colombier ex = -ex; 2158ccd4a63SDavid du Colombier dp += ex; 216*0d601874SDavid du Colombier if(dp < -Maxe){ 217*0d601874SDavid du Colombier errno = ERANGE; 218*0d601874SDavid du Colombier goto ret0; /* underflow by exp */ 219*0d601874SDavid du Colombier } else 2208ccd4a63SDavid du Colombier if(dp > +Maxe) 221*0d601874SDavid du Colombier goto retinf; /* overflow by exp */ 2228ccd4a63SDavid du Colombier 2238ccd4a63SDavid du Colombier /* 2248ccd4a63SDavid du Colombier * normalize the decimal ascii number 2258ccd4a63SDavid du Colombier * to range .[5-9][0-9]* e0 2268ccd4a63SDavid du Colombier */ 227*0d601874SDavid du Colombier bp = 0; /* binary exponent */ 2288ccd4a63SDavid du Colombier while(dp > 0) 2298ccd4a63SDavid du Colombier divascii(a, &na, &dp, &bp); 2308ccd4a63SDavid du Colombier while(dp < 0 || a[0] < '5') 2318ccd4a63SDavid du Colombier mulascii(a, &na, &dp, &bp); 2328ccd4a63SDavid du Colombier 2338ccd4a63SDavid du Colombier /* close approx by naive conversion */ 234*0d601874SDavid du Colombier mid[0] = 0; 235*0d601874SDavid du Colombier mid[1] = 1; 236*0d601874SDavid du Colombier for(i=0; c=a[i]; i++) { 237*0d601874SDavid du Colombier mid[0] = mid[0]*10 + (c-'0'); 238*0d601874SDavid du Colombier mid[1] = mid[1]*10; 239*0d601874SDavid du Colombier if(i >= 8) 240*0d601874SDavid du Colombier break; 2418ccd4a63SDavid du Colombier } 242*0d601874SDavid du Colombier low[0] = umuldiv(mid[0], One, mid[1]); 243*0d601874SDavid du Colombier hig[0] = umuldiv(mid[0]+1, One, mid[1]); 2448ccd4a63SDavid du Colombier for(i=1; i<Prec; i++) { 2458ccd4a63SDavid du Colombier low[i] = 0; 2468ccd4a63SDavid du Colombier hig[i] = One-1; 2478ccd4a63SDavid du Colombier } 2488ccd4a63SDavid du Colombier 2498ccd4a63SDavid du Colombier /* binary search for closest mantissa */ 2508ccd4a63SDavid du Colombier for(;;) { 2518ccd4a63SDavid du Colombier /* mid = (hig + low) / 2 */ 2528ccd4a63SDavid du Colombier c = 0; 2538ccd4a63SDavid du Colombier for(i=0; i<Prec; i++) { 2548ccd4a63SDavid du Colombier mid[i] = hig[i] + low[i]; 2558ccd4a63SDavid du Colombier if(c) 2568ccd4a63SDavid du Colombier mid[i] += One; 2578ccd4a63SDavid du Colombier c = mid[i] & 1; 2588ccd4a63SDavid du Colombier mid[i] >>= 1; 2598ccd4a63SDavid du Colombier } 2608ccd4a63SDavid du Colombier frnorm(mid); 2618ccd4a63SDavid du Colombier 2628ccd4a63SDavid du Colombier /* compare */ 2638ccd4a63SDavid du Colombier c = fpcmp(a, mid); 2648ccd4a63SDavid du Colombier if(c > 0) { 2658ccd4a63SDavid du Colombier c = 1; 2668ccd4a63SDavid du Colombier for(i=0; i<Prec; i++) 2678ccd4a63SDavid du Colombier if(low[i] != mid[i]) { 2688ccd4a63SDavid du Colombier c = 0; 2698ccd4a63SDavid du Colombier low[i] = mid[i]; 2708ccd4a63SDavid du Colombier } 2718ccd4a63SDavid du Colombier if(c) 272*0d601874SDavid du Colombier break; /* between mid and hig */ 2738ccd4a63SDavid du Colombier continue; 2748ccd4a63SDavid du Colombier } 2758ccd4a63SDavid du Colombier if(c < 0) { 2768ccd4a63SDavid du Colombier for(i=0; i<Prec; i++) 2778ccd4a63SDavid du Colombier hig[i] = mid[i]; 2788ccd4a63SDavid du Colombier continue; 2798ccd4a63SDavid du Colombier } 2808ccd4a63SDavid du Colombier 2818ccd4a63SDavid du Colombier /* only hard part is if even/odd roundings wants to go up */ 2828ccd4a63SDavid du Colombier c = mid[Prec-1] & (Sigbit-1); 2838ccd4a63SDavid du Colombier if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0) 2848ccd4a63SDavid du Colombier mid[Prec-1] -= c; 285*0d601874SDavid du Colombier break; /* exactly mid */ 2868ccd4a63SDavid du Colombier } 2878ccd4a63SDavid du Colombier 2888ccd4a63SDavid du Colombier /* normal rounding applies */ 2898ccd4a63SDavid du Colombier c = mid[Prec-1] & (Sigbit-1); 2908ccd4a63SDavid du Colombier mid[Prec-1] -= c; 2918ccd4a63SDavid du Colombier if(c >= Sigbit/2) { 2928ccd4a63SDavid du Colombier mid[Prec-1] += Sigbit; 2938ccd4a63SDavid du Colombier frnorm(mid); 2948ccd4a63SDavid du Colombier } 295*0d601874SDavid du Colombier goto out; 2968ccd4a63SDavid du Colombier 2978ccd4a63SDavid du Colombier ret0: 2988ccd4a63SDavid du Colombier return 0; 2998ccd4a63SDavid du Colombier 3008ccd4a63SDavid du Colombier retnan: 3018ccd4a63SDavid du Colombier return __NaN(); 3028ccd4a63SDavid du Colombier 3038ccd4a63SDavid du Colombier retinf: 304*0d601874SDavid du Colombier /* 305*0d601874SDavid du Colombier * Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */ 306*0d601874SDavid du Colombier errno = ERANGE; 3078ccd4a63SDavid du Colombier if(flag & Fsign) 308*0d601874SDavid du Colombier return -HUGE_VAL; 309*0d601874SDavid du Colombier return HUGE_VAL; 310*0d601874SDavid du Colombier 311*0d601874SDavid du Colombier out: 312*0d601874SDavid du Colombier d = 0; 313*0d601874SDavid du Colombier for(i=0; i<Prec; i++) 314*0d601874SDavid du Colombier d = d*One + mid[i]; 315*0d601874SDavid du Colombier if(flag & Fsign) 316*0d601874SDavid du Colombier d = -d; 317*0d601874SDavid du Colombier d = ldexp(d, bp - Prec*Nbits); 318*0d601874SDavid du Colombier if(d == 0){ /* underflow */ 319*0d601874SDavid du Colombier errno = ERANGE; 320*0d601874SDavid du Colombier } 321*0d601874SDavid du Colombier return d; 3228ccd4a63SDavid du Colombier } 3238ccd4a63SDavid du Colombier 3248ccd4a63SDavid du Colombier static void 3258ccd4a63SDavid du Colombier frnorm(ulong *f) 3268ccd4a63SDavid du Colombier { 3278ccd4a63SDavid du Colombier int i, c; 3288ccd4a63SDavid du Colombier 3298ccd4a63SDavid du Colombier c = 0; 3308ccd4a63SDavid du Colombier for(i=Prec-1; i>0; i--) { 3318ccd4a63SDavid du Colombier f[i] += c; 3328ccd4a63SDavid du Colombier c = f[i] >> Nbits; 3338ccd4a63SDavid du Colombier f[i] &= One-1; 3348ccd4a63SDavid du Colombier } 3358ccd4a63SDavid du Colombier f[0] += c; 3368ccd4a63SDavid du Colombier } 3378ccd4a63SDavid du Colombier 3388ccd4a63SDavid du Colombier static int 3398ccd4a63SDavid du Colombier fpcmp(char *a, ulong* f) 3408ccd4a63SDavid du Colombier { 3418ccd4a63SDavid du Colombier ulong tf[Prec]; 3428ccd4a63SDavid du Colombier int i, d, c; 3438ccd4a63SDavid du Colombier 3448ccd4a63SDavid du Colombier for(i=0; i<Prec; i++) 3458ccd4a63SDavid du Colombier tf[i] = f[i]; 3468ccd4a63SDavid du Colombier 3478ccd4a63SDavid du Colombier for(;;) { 3488ccd4a63SDavid du Colombier /* tf *= 10 */ 3498ccd4a63SDavid du Colombier for(i=0; i<Prec; i++) 3508ccd4a63SDavid du Colombier tf[i] = tf[i]*10; 3518ccd4a63SDavid du Colombier frnorm(tf); 3528ccd4a63SDavid du Colombier d = (tf[0] >> Nbits) + '0'; 3538ccd4a63SDavid du Colombier tf[0] &= One-1; 3548ccd4a63SDavid du Colombier 3558ccd4a63SDavid du Colombier /* compare next digit */ 3568ccd4a63SDavid du Colombier c = *a; 3578ccd4a63SDavid du Colombier if(c == 0) { 3588ccd4a63SDavid du Colombier if('0' < d) 3598ccd4a63SDavid du Colombier return -1; 3608ccd4a63SDavid du Colombier if(tf[0] != 0) 3618ccd4a63SDavid du Colombier goto cont; 3628ccd4a63SDavid du Colombier for(i=1; i<Prec; i++) 3638ccd4a63SDavid du Colombier if(tf[i] != 0) 3648ccd4a63SDavid du Colombier goto cont; 3658ccd4a63SDavid du Colombier return 0; 3668ccd4a63SDavid du Colombier } 3678ccd4a63SDavid du Colombier if(c > d) 3688ccd4a63SDavid du Colombier return +1; 3698ccd4a63SDavid du Colombier if(c < d) 3708ccd4a63SDavid du Colombier return -1; 3718ccd4a63SDavid du Colombier a++; 3728ccd4a63SDavid du Colombier cont:; 3738ccd4a63SDavid du Colombier } 3748ccd4a63SDavid du Colombier } 3758ccd4a63SDavid du Colombier 3768ccd4a63SDavid du Colombier static void 377*0d601874SDavid du Colombier divby(char *a, int *na, int b) 3788ccd4a63SDavid du Colombier { 3798ccd4a63SDavid du Colombier int n, c; 3808ccd4a63SDavid du Colombier char *p; 3818ccd4a63SDavid du Colombier 3828ccd4a63SDavid du Colombier p = a; 3838ccd4a63SDavid du Colombier n = 0; 3848ccd4a63SDavid du Colombier while(n>>b == 0) { 3858ccd4a63SDavid du Colombier c = *a++; 3868ccd4a63SDavid du Colombier if(c == 0) { 3878ccd4a63SDavid du Colombier while(n) { 3888ccd4a63SDavid du Colombier c = n*10; 3898ccd4a63SDavid du Colombier if(c>>b) 3908ccd4a63SDavid du Colombier break; 3918ccd4a63SDavid du Colombier n = c; 3928ccd4a63SDavid du Colombier } 3938ccd4a63SDavid du Colombier goto xx; 3948ccd4a63SDavid du Colombier } 3958ccd4a63SDavid du Colombier n = n*10 + c-'0'; 3968ccd4a63SDavid du Colombier (*na)--; 3978ccd4a63SDavid du Colombier } 3988ccd4a63SDavid du Colombier for(;;) { 3998ccd4a63SDavid du Colombier c = n>>b; 4008ccd4a63SDavid du Colombier n -= c<<b; 4018ccd4a63SDavid du Colombier *p++ = c + '0'; 4028ccd4a63SDavid du Colombier c = *a++; 4038ccd4a63SDavid du Colombier if(c == 0) 4048ccd4a63SDavid du Colombier break; 4058ccd4a63SDavid du Colombier n = n*10 + c-'0'; 4068ccd4a63SDavid du Colombier } 4078ccd4a63SDavid du Colombier (*na)++; 4088ccd4a63SDavid du Colombier xx: 4098ccd4a63SDavid du Colombier while(n) { 4108ccd4a63SDavid du Colombier n = n*10; 4118ccd4a63SDavid du Colombier c = n>>b; 4128ccd4a63SDavid du Colombier n -= c<<b; 4138ccd4a63SDavid du Colombier *p++ = c + '0'; 4148ccd4a63SDavid du Colombier (*na)++; 4158ccd4a63SDavid du Colombier } 4168ccd4a63SDavid du Colombier *p = 0; 4178ccd4a63SDavid du Colombier } 4188ccd4a63SDavid du Colombier 4198ccd4a63SDavid du Colombier static Tab tab1[] = 4208ccd4a63SDavid du Colombier { 4218ccd4a63SDavid du Colombier 1, 0, "", 4228ccd4a63SDavid du Colombier 3, 1, "7", 4238ccd4a63SDavid du Colombier 6, 2, "63", 4248ccd4a63SDavid du Colombier 9, 3, "511", 4258ccd4a63SDavid du Colombier 13, 4, "8191", 4268ccd4a63SDavid du Colombier 16, 5, "65535", 4278ccd4a63SDavid du Colombier 19, 6, "524287", 4288ccd4a63SDavid du Colombier 23, 7, "8388607", 4298ccd4a63SDavid du Colombier 26, 8, "67108863", 4308ccd4a63SDavid du Colombier 27, 9, "134217727", 4318ccd4a63SDavid du Colombier }; 4328ccd4a63SDavid du Colombier 4338ccd4a63SDavid du Colombier static void 4348ccd4a63SDavid du Colombier divascii(char *a, int *na, int *dp, int *bp) 4358ccd4a63SDavid du Colombier { 4368ccd4a63SDavid du Colombier int b, d; 4378ccd4a63SDavid du Colombier Tab *t; 4388ccd4a63SDavid du Colombier 4398ccd4a63SDavid du Colombier d = *dp; 440*0d601874SDavid du Colombier if(d >= (int)(nelem(tab1))) 441*0d601874SDavid du Colombier d = (int)(nelem(tab1))-1; 4428ccd4a63SDavid du Colombier t = tab1 + d; 4438ccd4a63SDavid du Colombier b = t->bp; 4448ccd4a63SDavid du Colombier if(memcmp(a, t->cmp, t->siz) > 0) 4458ccd4a63SDavid du Colombier d--; 4468ccd4a63SDavid du Colombier *dp -= d; 4478ccd4a63SDavid du Colombier *bp += b; 4488ccd4a63SDavid du Colombier divby(a, na, b); 4498ccd4a63SDavid du Colombier } 4508ccd4a63SDavid du Colombier 4518ccd4a63SDavid du Colombier static void 4528ccd4a63SDavid du Colombier mulby(char *a, char *p, char *q, int b) 4538ccd4a63SDavid du Colombier { 4548ccd4a63SDavid du Colombier int n, c; 4558ccd4a63SDavid du Colombier 4568ccd4a63SDavid du Colombier n = 0; 4578ccd4a63SDavid du Colombier *p = 0; 4588ccd4a63SDavid du Colombier for(;;) { 4598ccd4a63SDavid du Colombier q--; 4608ccd4a63SDavid du Colombier if(q < a) 4618ccd4a63SDavid du Colombier break; 4628ccd4a63SDavid du Colombier c = *q - '0'; 4638ccd4a63SDavid du Colombier c = (c<<b) + n; 4648ccd4a63SDavid du Colombier n = c/10; 4658ccd4a63SDavid du Colombier c -= n*10; 4668ccd4a63SDavid du Colombier p--; 4678ccd4a63SDavid du Colombier *p = c + '0'; 4688ccd4a63SDavid du Colombier } 4698ccd4a63SDavid du Colombier while(n) { 4708ccd4a63SDavid du Colombier c = n; 4718ccd4a63SDavid du Colombier n = c/10; 4728ccd4a63SDavid du Colombier c -= n*10; 4738ccd4a63SDavid du Colombier p--; 4748ccd4a63SDavid du Colombier *p = c + '0'; 4758ccd4a63SDavid du Colombier } 4768ccd4a63SDavid du Colombier } 4778ccd4a63SDavid du Colombier 4788ccd4a63SDavid du Colombier static Tab tab2[] = 4798ccd4a63SDavid du Colombier { 480*0d601874SDavid du Colombier 1, 1, "", /* dp = 0-0 */ 4818ccd4a63SDavid du Colombier 3, 3, "125", 4828ccd4a63SDavid du Colombier 6, 5, "15625", 4838ccd4a63SDavid du Colombier 9, 7, "1953125", 4848ccd4a63SDavid du Colombier 13, 10, "1220703125", 4858ccd4a63SDavid du Colombier 16, 12, "152587890625", 4868ccd4a63SDavid du Colombier 19, 14, "19073486328125", 4878ccd4a63SDavid du Colombier 23, 17, "11920928955078125", 4888ccd4a63SDavid du Colombier 26, 19, "1490116119384765625", 489*0d601874SDavid du Colombier 27, 19, "7450580596923828125", /* dp 8-9 */ 4908ccd4a63SDavid du Colombier }; 4918ccd4a63SDavid du Colombier 4928ccd4a63SDavid du Colombier static void 4938ccd4a63SDavid du Colombier mulascii(char *a, int *na, int *dp, int *bp) 4948ccd4a63SDavid du Colombier { 4958ccd4a63SDavid du Colombier char *p; 4968ccd4a63SDavid du Colombier int d, b; 4978ccd4a63SDavid du Colombier Tab *t; 4988ccd4a63SDavid du Colombier 4998ccd4a63SDavid du Colombier d = -*dp; 500*0d601874SDavid du Colombier if(d >= (int)(nelem(tab2))) 501*0d601874SDavid du Colombier d = (int)(nelem(tab2))-1; 5028ccd4a63SDavid du Colombier t = tab2 + d; 5038ccd4a63SDavid du Colombier b = t->bp; 5048ccd4a63SDavid du Colombier if(memcmp(a, t->cmp, t->siz) < 0) 5058ccd4a63SDavid du Colombier d--; 5068ccd4a63SDavid du Colombier p = a + *na; 5078ccd4a63SDavid du Colombier *bp -= b; 5088ccd4a63SDavid du Colombier *dp += d; 5098ccd4a63SDavid du Colombier *na += d; 5108ccd4a63SDavid du Colombier mulby(a, p+d, p, b); 5118ccd4a63SDavid du Colombier } 5128ccd4a63SDavid du Colombier 5138ccd4a63SDavid du Colombier static int 5148ccd4a63SDavid du Colombier xcmp(char *a, char *b) 5158ccd4a63SDavid du Colombier { 5168ccd4a63SDavid du Colombier int c1, c2; 5178ccd4a63SDavid du Colombier 5188ccd4a63SDavid du Colombier while((c1 = *b++)) { 5198ccd4a63SDavid du Colombier c2 = *a++; 5208ccd4a63SDavid du Colombier if(isupper(c2)) 5218ccd4a63SDavid du Colombier c2 = tolower(c2); 5228ccd4a63SDavid du Colombier if(c1 != c2) 5238ccd4a63SDavid du Colombier return 1; 5248ccd4a63SDavid du Colombier } 5258ccd4a63SDavid du Colombier return 0; 5268ccd4a63SDavid du Colombier } 527