Annotation of 43BSD/contrib/B/src/bint/b1nuC.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
                      2: 
                      3: /*
                      4:   $Header: b1nuC.c,v 1.4 85/08/22 16:50:36 timo Exp $
                      5: */
                      6: 
                      7: #include <ctype.h>
                      8: #include "b.h"
                      9: #include "b0con.h"
                     10: #include "b0fea.h"
                     11: #include "b1obj.h"
                     12: #include "b1mem.h"
                     13: #include "b1num.h"
                     14: #include "b2syn.h" /* temporary until numconst is fixed */
                     15: 
                     16: char *sprintf(); /* OS */
                     17: extern value tento();
                     18: extern integer int_tento();
                     19: 
                     20: #define EXPDIGITS 10   /* Extra positions to allow for exponent part */
                     21:                        /* -- must be larger than tenlogBASE */
                     22: #define MAXDIGITS (MAXNUMDIG-1)        /* Max precision for fixed/floating numbers */
                     23: #define CONVBUFSIZE (MAXDIGITS+4)
                     24:                        /* Maximum number of digits to print in integer notation */
                     25:                        /* (4 is the size of 'e+00' added by sprintf) */
                     26: 
                     27: 
                     28: /* Convert an integer to a C character string.
                     29:    The character string is overwritten on each next call.
                     30:    It assumes BASE is a power of 10. */
                     31: 
                     32: Hidden char *convint(v) register integer v; {
                     33:        static char *buffer, shortbuffer[tenlogBASE+3];
                     34:        static char fmt[10];
                     35:        register char *cp;
                     36:        register int i;
                     37:        bool neg = No;
                     38: 
                     39:        if (IsSmallInt(v)) {
                     40:                sprintf(shortbuffer, "%d", SmallIntVal(v));
                     41:                return shortbuffer;
                     42:        }
                     43: 
                     44:        if (Digit(v, Length(v)-1) < 0) {
                     45:                neg = Yes;
                     46:                v = int_neg(v);
                     47:        }
                     48:        if (buffer) freemem(buffer);
                     49:        buffer = getmem((unsigned)(Length(v)*tenlogBASE + 1 + neg));
                     50:        cp = buffer;
                     51:        if (neg) *cp++ = '-';
                     52:        sprintf(cp, "%d", Msd(v));
                     53:        if (!IsSmallInt(v)) {
                     54:                if (!*fmt) sprintf(fmt, "%%0%dd", tenlogBASE);
                     55:                while (*cp) ++cp;
                     56:                for (i = Length(v)-2; i >= 0; --i, cp += tenlogBASE)
                     57:                        sprintf(cp, fmt, Digit(v, i));
                     58:                if (neg) release((value) v);
                     59:        }
                     60:        return buffer;
                     61: }
                     62: 
                     63: #ifdef EXT_RANGE
                     64: 
                     65: /* This is terrible.  But never mind, it'll all change (sometimes). */
                     66: 
                     67: Hidden bool hugenumber(v) value v; {
                     68:        bool huge;
                     69:        real w = (real) approximate(v);
                     70:        huge = Expo(w) > Maxexpo || Expo(w) < Minexpo && Frac(w) != 0;
                     71:        release((value)w);
                     72:        return huge;
                     73: }
                     74: 
                     75: 
                     76: Hidden string convapp(v) value v; {
                     77:        value absv, tenlogv, expo, tentoexpo, frac;
                     78:        static char buf[100];
                     79:        char fmt[15];
                     80:        int precision;
                     81:        double fracval, expoval, i;
                     82: 
                     83:        absv = absval(v);
                     84:        tenlogv = log2((value)int_10, absv), release(absv);
                     85:        expo = floorf(tenlogv), release(tenlogv);
                     86:        expoval = numval(expo), release(expo);
                     87:        if (expoval*tenlogBASE >= Maxintlet || expoval*tenlogBASE <= -Maxintlet) {
                     88:                expo = (value) mk_approx(expoval, 0.0);
                     89:                tentoexpo = power((value)int_10, expo), release(expo);
                     90:        }
                     91:        else
                     92:                tentoexpo = tento((int)expoval);
                     93:        frac = quot(v, tentoexpo), release(tentoexpo);
                     94:        fracval = numval(frac), release(frac);
                     95:        while (fabs(fracval) >= 10) fracval /= 10, ++expoval;
                     96:        while (fabs(fracval) < 1) fracval *= 10, --expoval;
                     97:        precision = MAXDIGITS;
                     98:        i = expoval < 0 ? -expoval : expoval;
                     99:        while (i >= 10 && precision > 2) --precision, i /= 10;
                    100:                /* Loose precision for large exponents! */
                    101:                /* :-( But keep some too! )-: */
                    102:        sprintf(fmt, "%%.%dlgE%%s%%2.0lf", precision);
                    103:        sprintf(buf, fmt, fracval, expoval >= 0 ? "+" : "", expoval);
                    104:        return buf;
                    105: }
                    106: 
                    107: #endif EXT_RANGE
                    108: 
                    109: /* Convert a numeric value to a C character string.
                    110:    The character string is overwritten on each next call. */
                    111: 
                    112: Visible string convnum(v) register value v; {
                    113:        static char convbuf[3+CONVBUFSIZE+EXPDIGITS];
                    114:                /* 3 extra for things (sign, 0.) to be stuck on front of it */
                    115:        static char fmt[10];
                    116:        char *bufstart = convbuf+3;
                    117:        register char *cp = bufstart;
                    118:        double x;
                    119: 
                    120:        if (Integral(v)) return convint((integer)v);
                    121: #ifdef EXT_RANGE
                    122:        if (hugenumber(v)) return convapp(v);
                    123: #endif
                    124: 
                    125:        /* Reasonably-sized reals and rationals are treated alike.
                    126:           However, not-too-large rationals resulting from
                    127:           'n round x' are transformed to f-format. */
                    128: 
                    129:        x = numval(v);
                    130:        if (!*fmt) sprintf(fmt, "%%.%dlg", MAXDIGITS);
                    131:        sprintf(bufstart, fmt, x);
                    132: 
                    133:        for (cp = bufstart; *cp != '\0'; ++cp)
                    134:                if (*cp == 'e') {       /* change sprintf's 'e' to 'E' */
                    135:                        *cp = 'E';
                    136:                        break;
                    137:                }
                    138: 
                    139: #ifdef IBMPC
                    140:        if (*cp != 'E') {
                    141:                /* Delete trailing zeros after decimal pt; don't rely on %g */
                    142:                for (cp = bufstart; *cp != '\0' && *cp != '.'; ++cp)
                    143:                        ;
                    144:                if (*cp == '.') {
                    145:                        char *ep;
                    146:                        for (; *cp != '\0' && *cp != 'E'; ++cp)
                    147:                                ;
                    148:                        ep = cp;
                    149:                        while (*--cp == '0')
                    150:                                ;
                    151:                        if (++cp < ep) {
                    152:                                while (*ep != '\0')
                    153:                                        *cp++ = *ep++;
                    154:                                *cp = '\0';
                    155:                        }
                    156:                }
                    157:        }
                    158: #endif IBMPC
                    159: 
                    160:        if (Rational(v) && Roundsize(v) > 0 && *cp != 'E') {
                    161:                int i = Roundsize(v);
                    162:                int j = 1;
                    163:                        /* Counts digits allowed beyond MAXDIGITS, 1 for '.' */
                    164: 
                    165:                for (cp = bufstart; *cp == '0'; ++cp)
                    166:                        ++j; /* Allow a trailing zero for each leading zero */
                    167: 
                    168:                for (; *cp != '\0' && *cp != '.'; ++cp)
                    169:                        ; /* Find '.' or end of string */
                    170: 
                    171:                if (*cp == '\0') {
                    172:                        *cp = '.'; /* Append '.' if not found */
                    173:                        *++cp = '\0';
                    174:                }
                    175:                else {
                    176:                        while (*++cp == '0')
                    177:                                /* Allow more precision if leading zeros */
                    178:                                ++j, --i;
                    179:                        while (*cp != '\0')
                    180:                                --i, ++cp; /* Find last digit */
                    181:                }
                    182: 
                    183:                /* Append extra zeros (but don't show more precision
                    184:                   than sprintf can!) */
                    185:                while (--i >= 0 && cp < bufstart+MAXDIGITS+j)
                    186:                        *cp++ = '0';
                    187: 
                    188:                *cp = '\0'; /* Append new terminating null byte */
                    189:        }
                    190: 
                    191:        return bufstart;
                    192: }
                    193: 
                    194: 
                    195: /* Convert a string to a number (assume it's syntactically correct!).
                    196:    Pointers to the first and last+1 characters are given.
                    197:    Again, BASE must be a power of 10.
                    198:    ********** NEW **********
                    199:    If E_EXACT is defined, all numbers input are made exact, even if
                    200:    E-notation is used.
                    201:    ********** WARNING **********
                    202:    This routine must be fixed, because it accesses the source buffer
                    203:    and it shouldn't because it's in the wrong place in the hierarchy
                    204: */
                    205: 
                    206: Visible value numconst(text, end) register txptr text, end; {
                    207:        register txptr tp;
                    208:        register int numdigs, fraclen;
                    209:        integer a;
                    210:        register digit accu;
                    211:        value c;
                    212: 
                    213:        if (Char(text) == 'E') a = int_1;
                    214:        else {
                    215:                while (text<end && Char(text)=='0') ++text; /* Skip leading zeros */
                    216: 
                    217:                for (tp = text; tp<end && isdigit(Char(tp)); ++tp)
                    218:                        ; /* Count integral digits */
                    219:                numdigs = tp-text;
                    220:                fraclen = 0;
                    221:                if (tp<end && Char(tp)=='.') {
                    222:                        ++tp;
                    223:                        for (; tp<end && isdigit(Char(tp)); ++tp)
                    224:                                ++fraclen; /* Count fractional digits */
                    225:                        numdigs += fraclen;
                    226:                }
                    227:                a = (integer) grab_num((numdigs+tenlogBASE-1) / tenlogBASE);
                    228:                if (!a) return Vnil; /* Recovered error */
                    229:                accu = 0;
                    230:                /* Integer part: */
                    231:                for (; text<end && isdigit(Char(text)); ++text) {
                    232:                        accu = accu*10 + Char(text)-'0';
                    233:                        --numdigs;
                    234:                        if (numdigs%tenlogBASE == 0) {
                    235:                                Digit(a, numdigs/tenlogBASE) = accu;
                    236:                                accu = 0;
                    237:                        }
                    238:                }
                    239:                /* Fraction: */
                    240:                if (text < end && Char(text) == '.') {
                    241:                        ++text;
                    242:                        for (; text<end && isdigit(Char(text)); ++text) {
                    243:                                accu = accu*10 + Char(text)-'0';
                    244:                                --numdigs;
                    245:                                if (numdigs%tenlogBASE == 0) {
                    246:                                        Digit(a, numdigs/tenlogBASE) = accu;
                    247:                                        accu = 0;
                    248:                                }
                    249:                        }
                    250:                }
                    251:                if (numdigs != 0) syserr(MESS(800, "numconst: can't happen"));
                    252:                a = int_canon(a);
                    253:        }
                    254: 
                    255:        /* Exponent: */
                    256:        if (text >= end || Char(text) != 'E') {
                    257:                integer b = int_tento(fraclen);
                    258:                c = mk_exact(a, b, fraclen);
                    259:                release((value) b);
                    260:        }
                    261:        else {
                    262:                double expo = 0;
                    263:                int sign = 1;
                    264:                value b;
                    265:                ++text;
                    266:                if (text < end) {
                    267:                        if (Char(text) == '+') ++text;
                    268:                        else if (Char(text) == '-') {
                    269:                                ++text;
                    270:                                sign = -1;
                    271:                        }
                    272:                }
                    273:                for (; text<end && isdigit(Char(text)); ++text) {
                    274:                        expo = expo*10 + Char(text)-'0';
                    275:                        if (expo > Maxint) {
                    276:                                error(MESS(801, "excessive exponent in E-notation"));
                    277:                                expo = 0;
                    278:                                break;
                    279:                        }
                    280:                }
                    281:                b = tento((int)expo * sign - fraclen);
                    282: #ifndef E_EXACT
                    283:                /* Make approximate number if E-notation used */
                    284:                c = approximate(b);
                    285:                release(b);
                    286:                b = c;
                    287: #endif
                    288:                if (a == int_1) c = b;
                    289:                else c = prod((value)a, b), release(b);
                    290:        }
                    291:        release((value) a);
                    292:        return c;
                    293: }
                    294: 
                    295: 
                    296: /*
                    297:  * printnum(f, v) writes a number v on file f in such a way that it
                    298:  * can be read back identically, assuming integral powers of ~2 can be
                    299:  * computed exactly.  (This is necessary for the permanent environment.)
                    300:  */
                    301: 
                    302: Visible Procedure printnum(f, v) FILE *f; value v; {
                    303:        if (Approximate(v)) {
                    304: #ifdef PRINT_APPROX
                    305:                if (Frac((real)v) == 0) fprintf(f, "~0");
                    306:                else {
                    307:                        static char fmt[25];
                    308:                        if (!*fmt)
                    309:                            sprintf(fmt, "%%.%dlgE0*~2**%%.0lf", MAXDIGITS+2);
                    310:                        fprintf(f, fmt, Frac((real)v), Expo((real)v));
                    311:                }
                    312:                return;
                    313: #else
                    314:                fputc('~', f);
                    315: #endif
                    316:        }
                    317:        if (Rational(v) && Denominator((rational)v) != int_1) {
                    318:                int i = Roundsize(v);
                    319:                fputs(convnum((value)Numerator((rational)v)), f);
                    320:                if (i > 0 && i <= MAXDIGITS) {
                    321:                        /* The assumption here is that in u/v, the Roundsize
                    322:                           of the result is the sum of that of the operands. */
                    323:                        putc('.', f);
                    324:                        do putc('0', f); while (--i > 0);
                    325:                }
                    326:                putc('/', f);
                    327:                v = (value) Denominator((rational)v);
                    328:        }
                    329:        fputs(convnum(v), f);
                    330: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.