|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.