|
|
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.