modified: diffout.py
[GalaxyCodeBases.git] / c_cpp / etc / calc / qio.c
blob3c57f2fbedbb79d590651d563b01b89bb4fc54fb
1 /*
2 * qio - scanf and printf routines for arbitrary precision rational numbers
4 * Copyright (C) 1999-2007 David I. Bell
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.1 $
21 * @(#) $Id: qio.c,v 30.1 2007/03/16 11:09:46 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/RCS/qio.c,v $
24 * Under source code control: 1993/07/30 19:42:46
25 * File existed as early as: 1993
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
31 #include "qmath.h"
32 #include "config.h"
33 #include "args.h"
35 #include "have_unused.h"
38 #define PUTCHAR(ch) math_chr(ch)
39 #define PUTSTR(str) math_str(str)
40 #define PRINTF1(fmt, a1) math_fmt(fmt, a1)
41 #define PRINTF2(fmt, a1, a2) math_fmt(fmt, a1, a2)
43 STATIC long scalefactor;
44 STATIC ZVALUE scalenumber = { 0, 0, 0 };
48 * Print a formatted string containing arbitrary numbers, similar to printf.
49 * ALL numeric arguments to this routine are rational NUMBERs.
50 * Various forms of printing such numbers are supplied, in addition
51 * to strings and characters. Output can actually be to any FILE
52 * stream or a string.
54 void
55 qprintf(char *fmt, ...)
57 va_list ap;
58 NUMBER *q;
59 int ch, sign = 1;
60 long width = 0, precision = 0;
61 int trigger = 0;
63 va_start(ap, fmt);
64 while ((ch = *fmt++) != '\0') {
65 if (trigger == 0) {
66 if (ch == '\\') {
67 ch = *fmt++;
68 switch (ch) {
69 case 'n': ch = '\n'; break;
70 case 'r': ch = '\r'; break;
71 case 't': ch = '\t'; break;
72 case 'f': ch = '\f'; break;
73 case 'v': ch = '\v'; break;
74 case 'b': ch = '\b'; break;
75 case 0:
76 va_end(ap);
77 return;
79 PUTCHAR(ch);
80 continue;
82 if (ch != '%') {
83 PUTCHAR(ch);
84 continue;
86 ch = *fmt++;
87 width = 0; precision = 8; sign = 1;
88 trigger = 1;
91 switch (ch) {
92 case 'd':
93 q = va_arg(ap, NUMBER *);
94 qprintfd(q, width);
95 break;
96 case 'f':
97 q = va_arg(ap, NUMBER *);
98 qprintff(q, width, precision);
99 break;
100 case 'e':
101 q = va_arg(ap, NUMBER *);
102 qprintfe(q, width, precision);
103 break;
104 case 'r':
105 case 'R':
106 q = va_arg(ap, NUMBER *);
107 qprintfr(q, width, (BOOL) (ch == 'R'));
108 break;
109 case 'N':
110 q = va_arg(ap, NUMBER *);
111 zprintval(q->num, 0L, width);
112 break;
113 case 'D':
114 q = va_arg(ap, NUMBER *);
115 zprintval(q->den, 0L, width);
116 break;
117 case 'o':
118 q = va_arg(ap, NUMBER *);
119 qprintfo(q, width);
120 break;
121 case 'x':
122 q = va_arg(ap, NUMBER *);
123 qprintfx(q, width);
124 break;
125 case 'b':
126 q = va_arg(ap, NUMBER *);
127 qprintfb(q, width);
128 break;
129 case 's':
130 PUTSTR(va_arg(ap, char *));
131 break;
132 case 'c':
133 PUTCHAR(va_arg(ap, int));
134 break;
135 case 0:
136 va_end(ap);
137 return;
138 case '-':
139 sign = -1;
140 ch = *fmt++;
141 default:
142 if (('0' <= ch && ch <= '9') ||
143 ch == '.' || ch == '*') {
144 if (ch == '*') {
145 q = va_arg(ap, NUMBER *);
146 width = sign * qtoi(q);
147 ch = *fmt++;
148 } else if (ch != '.') {
149 width = ch - '0';
150 while ('0' <= (ch = *fmt++) &&
151 ch <= '9')
152 width = width * 10 + ch - '0';
153 width *= sign;
155 if (ch == '.') {
156 if ((ch = *fmt++) == '*') {
157 q = va_arg(ap, NUMBER *);
158 precision = qtoi(q);
159 ch = *fmt++;
160 } else {
161 precision = 0;
162 while ('0' <= (ch = *fmt++) &&
163 ch <= '9')
164 precision *= 10+ch-'0';
170 va_end(ap);
175 * Print a number in the specified output mode.
176 * If MODE_DEFAULT is given, then the default output mode is used.
177 * Any approximate output is flagged with a leading tilde.
178 * Integers are always printed as themselves.
180 void
181 qprintnum(NUMBER *q, int outmode)
183 NUMBER tmpval;
184 long prec, exp;
185 int outmode2 = MODE2_OFF;
187 if (outmode == MODE_DEFAULT) {
188 outmode = conf->outmode;
189 outmode2 = conf->outmode2;
191 switch (outmode) {
192 case MODE_INT:
193 if (conf->tilde_ok && qisfrac(q))
194 PUTCHAR('~');
195 qprintfd(q, 0L);
196 break;
198 case MODE_REAL:
199 prec = qdecplaces(q);
200 if ((prec < 0) || (prec > conf->outdigits)) {
201 if (conf->tilde_ok)
202 PUTCHAR('~');
204 if (conf->fullzero || (prec < 0) ||
205 (prec > conf->outdigits))
206 prec = conf->outdigits;
207 qprintff(q, 0L, prec);
208 break;
210 case MODE_FRAC:
211 qprintfr(q, 0L, FALSE);
212 break;
214 case MODE_EXP:
215 if (qiszero(q)) {
216 PUTCHAR('0');
217 return;
219 tmpval = *q;
220 tmpval.num.sign = 0;
221 exp = qilog10(&tmpval);
222 if (exp == 0) { /* in range to output as real */
223 qprintnum(q, MODE_REAL);
224 return;
226 tmpval.num = _one_;
227 tmpval.den = _one_;
228 if (exp > 0)
229 ztenpow(exp, &tmpval.den);
230 else
231 ztenpow(-exp, &tmpval.num);
232 q = qmul(q, &tmpval);
233 zfree(tmpval.num);
234 zfree(tmpval.den);
235 qprintnum(q, MODE_REAL);
236 qfree(q);
237 PRINTF1("e%ld", exp);
238 break;
240 case MODE_HEX:
241 qprintfx(q, 0L);
242 break;
244 case MODE_OCTAL:
245 qprintfo(q, 0L);
246 break;
248 case MODE_BINARY:
249 qprintfb(q, 0L);
250 break;
252 default:
253 math_error("Bad mode for print");
254 /*NOTREACHED*/
257 if (outmode2 != MODE2_OFF) {
258 PUTSTR(" /* ");
259 qprintnum(q, outmode2);
260 PUTSTR(" */");
266 * Print a number in floating point representation.
267 * Example: 193.784
269 void
270 qprintff(NUMBER *q, long width, long precision)
272 ZVALUE z, z1;
274 if (precision != scalefactor) {
275 if (scalenumber.v)
276 zfree(scalenumber);
277 ztenpow(precision, &scalenumber);
278 scalefactor = precision;
280 if (scalenumber.v)
281 zmul(q->num, scalenumber, &z);
282 else
283 z = q->num;
284 if (qisfrac(q)) {
285 zquo(z, q->den, &z1, conf->outround);
286 if (z.v != q->num.v)
287 zfree(z);
288 z = z1;
290 if (qisneg(q) && ziszero(z))
291 PUTCHAR('-');
292 zprintval(z, precision, width);
293 if (z.v != q->num.v)
294 zfree(z);
299 * Print a number in exponential notation.
300 * Example: 4.1856e34
302 /*ARGSUSED*/
303 void
304 qprintfe(NUMBER *q, long UNUSED width, long precision)
306 long exponent;
307 NUMBER q2;
308 ZVALUE num, zden, tenpow, tmp;
310 if (qiszero(q)) {
311 PUTSTR("0.0");
312 return;
314 num = q->num;
315 zden = q->den;
316 num.sign = 0;
317 exponent = zdigits(num) - zdigits(zden);
318 if (exponent > 0) {
319 ztenpow(exponent, &tenpow);
320 zmul(zden, tenpow, &tmp);
321 zfree(tenpow);
322 zden = tmp;
324 if (exponent < 0) {
325 ztenpow(-exponent, &tenpow);
326 zmul(num, tenpow, &tmp);
327 zfree(tenpow);
328 num = tmp;
330 if (zrel(num, zden) < 0) {
331 zmuli(num, 10L, &tmp);
332 if (num.v != q->num.v)
333 zfree(num);
334 num = tmp;
335 exponent--;
337 q2.num = num;
338 q2.den = zden;
339 q2.num.sign = q->num.sign;
340 qprintff(&q2, 0L, precision);
341 if (exponent)
342 PRINTF1("e%ld", exponent);
343 if (num.v != q->num.v)
344 zfree(num);
345 if (zden.v != q->den.v)
346 zfree(zden);
351 * Print a number in rational representation.
352 * Example: 397/37
354 void
355 qprintfr(NUMBER *q, long width, BOOL force)
357 zprintval(q->num, 0L, width);
358 if (force || qisfrac(q)) {
359 PUTCHAR('/');
360 zprintval(q->den, 0L, width);
366 * Print a number as an integer (truncating fractional part).
367 * Example: 958421
369 void
370 qprintfd(NUMBER *q, long width)
372 ZVALUE z;
374 if (qisfrac(q)) {
375 zquo(q->num, q->den, &z, conf->outround);
376 zprintval(z, 0L, width);
377 zfree(z);
378 } else {
379 zprintval(q->num, 0L, width);
385 * Print a number in hex.
386 * This prints the numerator and denominator in hex.
388 void
389 qprintfx(NUMBER *q, long width)
391 zprintx(q->num, width);
392 if (qisfrac(q)) {
393 PUTCHAR('/');
394 zprintx(q->den, 0L);
400 * Print a number in binary.
401 * This prints the numerator and denominator in binary.
403 void
404 qprintfb(NUMBER *q, long width)
406 zprintb(q->num, width);
407 if (qisfrac(q)) {
408 PUTCHAR('/');
409 zprintb(q->den, 0L);
415 * Print a number in octal.
416 * This prints the numerator and denominator in octal.
418 void
419 qprintfo(NUMBER *q, long width)
421 zprinto(q->num, width);
422 if (qisfrac(q)) {
423 PUTCHAR('/');
424 zprinto(q->den, 0L);
430 * Convert a string to a number in rational, floating point,
431 * exponential notation, hex, or octal.
432 * q = str2q(string);
434 NUMBER *
435 str2q(char *s)
437 register NUMBER *q;
438 register char *t;
439 ZVALUE div, newnum, newden, tmp;
440 long decimals, exp;
441 BOOL hex, negexp;
443 q = qalloc();
444 decimals = 0;
445 exp = 0;
446 negexp = FALSE;
447 hex = FALSE;
448 t = s;
449 if ((*t == '+') || (*t == '-'))
450 t++;
451 if ((*t == '0') && ((t[1] == 'x') || (t[1] == 'X'))) {
452 hex = TRUE;
453 t += 2;
455 while (((*t >= '0') && (*t <= '9')) || (hex &&
456 (((*t >= 'a') && (*t <= 'f')) || ((*t >= 'A') && (*t <= 'F')))))
457 t++;
458 if (*t == '/') {
459 t++;
460 str2z(t, &q->den);
461 } else if ((*t == '.') || (*t == 'e') || (*t == 'E')) {
462 if (*t == '.') {
463 t++;
464 while ((*t >= '0') && (*t <= '9')) {
465 t++;
466 decimals++;
470 * Parse exponent if any
472 if ((*t == 'e') || (*t == 'E')) {
473 t++;
474 if (*t == '+')
475 t++;
476 else if (*t == '-') {
477 negexp = TRUE;
478 t++;
480 while ((*t >= '0') && (*t <= '9')) {
481 exp = (exp * 10) + *t++ - '0';
482 if (exp > (MAXLONG/10L)) {
483 math_error("Exponent too large");
484 /*NOTREACHED*/
488 ztenpow(decimals, &q->den);
490 str2z(s, &q->num);
491 if (qiszero(q)) {
492 qfree(q);
493 return qlink(&_qzero_);
496 * Apply the exponential if any
498 if (exp) {
499 ztenpow(exp, &tmp);
500 if (negexp) {
501 zmul(q->den, tmp, &newden);
502 zfree(q->den);
503 q->den = newden;
504 } else {
505 zmul(q->num, tmp, &newnum);
506 zfree(q->num);
507 q->num = newnum;
509 zfree(tmp);
512 * Reduce the fraction to lowest terms
514 if (!zisunit(q->num) && !zisunit(q->den)) {
515 zgcd(q->num, q->den, &div);
516 if (!zisunit(div)) {
517 zequo(q->num, div, &newnum);
518 zfree(q->num);
519 zequo(q->den, div, &newden);
520 zfree(q->den);
521 q->num = newnum;
522 q->den = newden;
524 zfree(div);
526 return q;
531 * Parse a number in any of the various legal forms, and return the count
532 * of characters that are part of a legal number. Numbers can be either a
533 * decimal integer, possibly two decimal integers separated with a slash, a
534 * floating point or exponential number, a hex number beginning with "0x",
535 * a binary number beginning with "0b", or an octal number beginning with "0".
536 * The flags argument modifies the end of number testing for ease in handling
537 * fractions or complex numbers. Minus one is returned if the number format
538 * is definitely illegal.
540 long
541 qparse(char *cp, int flags)
543 char *oldcp;
545 oldcp = cp;
546 if ((*cp == '+') || (*cp == '-'))
547 cp++;
548 if ((*cp == '+') || (*cp == '-'))
549 return -1;
551 /* hex */
552 if ((*cp == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
553 cp += 2;
554 while (((*cp >= '0') && (*cp <= '9')) ||
555 ((*cp >= 'a') && (*cp <= 'f')) ||
556 ((*cp >= 'A') && (*cp <= 'F')))
557 cp++;
558 if (((*cp == 'i') || (*cp == 'I')) && (flags & QPF_IMAG))
559 cp++;
560 if ((*cp == '.') || ((*cp == '/') && (flags & QPF_SLASH)) ||
561 ((*cp >= '0') && (*cp <= '9')) ||
562 ((*cp >= 'a') && (*cp <= 'z')) ||
563 ((*cp >= 'A') && (*cp <= 'Z')))
564 return -1;
565 return (cp - oldcp);
568 /* binary */
569 if ((*cp == '0') && ((cp[1] == 'b') || (cp[1] == 'B'))) {
570 cp += 2;
571 while ((*cp == '0') || (*cp == '1'))
572 cp++;
573 if (((*cp == 'i') || (*cp == 'I')) && (flags & QPF_IMAG))
574 cp++;
575 if ((*cp == '.') || ((*cp == '/') && (flags & QPF_SLASH)) ||
576 ((*cp >= '0') && (*cp <= '9')) ||
577 ((*cp >= 'a') && (*cp <= 'z')) ||
578 ((*cp >= 'A') && (*cp <= 'Z')))
579 return -1;
580 return (cp - oldcp);
583 /* octal */
584 if ((*cp == '0') && (cp[1] >= '0') && (cp[1] <= '9')) {
585 while ((*cp >= '0') && (*cp <= '7'))
586 cp++;
587 if (((*cp == 'i') || (*cp == 'I')) && (flags & QPF_IMAG))
588 cp++;
589 if ((*cp == '.') || ((*cp == '/') && (flags & QPF_SLASH)) ||
590 ((*cp >= '0') && (*cp <= '9')) ||
591 ((*cp >= 'a') && (*cp <= 'z')) ||
592 ((*cp >= 'A') && (*cp <= 'Z')))
593 return -1;
594 return (cp - oldcp);
598 * Number is decimal but can still be a fraction or real or exponential
600 while ((*cp >= '0') && (*cp <= '9'))
601 cp++;
602 if (*cp == '/' && flags & QPF_SLASH) { /* fraction */
603 cp++;
604 while ((*cp >= '0') && (*cp <= '9'))
605 cp++;
606 if (((*cp == 'i') || (*cp == 'I')) && (flags & QPF_IMAG))
607 cp++;
608 if ((*cp == '.') || ((*cp == '/') && (flags & QPF_SLASH)) ||
609 ((*cp >= '0') && (*cp <= '9')) ||
610 ((*cp >= 'a') && (*cp <= 'z')) ||
611 ((*cp >= 'A') && (*cp <= 'Z')))
612 return -1;
613 return (cp - oldcp);
615 if (*cp == '.') { /* floating point */
616 cp++;
617 while ((*cp >= '0') && (*cp <= '9'))
618 cp++;
620 if ((*cp == 'e') || (*cp == 'E')) { /* exponential */
621 cp++;
622 if ((*cp == '+') || (*cp == '-'))
623 cp++;
624 if ((*cp == '+') || (*cp == '-'))
625 return -1;
626 while ((*cp >= '0') && (*cp <= '9'))
627 cp++;
630 if (((*cp == 'i') || (*cp == 'I')) && (flags & QPF_IMAG))
631 cp++;
632 if ((*cp == '.') || ((*cp == '/') && (flags & QPF_SLASH)) ||
633 ((*cp >= '0') && (*cp <= '9')) ||
634 ((*cp >= 'a') && (*cp <= 'z')) ||
635 ((*cp >= 'A') && (*cp <= 'Z')))
636 return -1;
637 return (cp - oldcp);
642 * Print an integer which is guaranteed to fit in the specified number
643 * of columns, using embedded '...' characters if numerator and/or
644 * denominator is too large.
646 void
647 fitprint(NUMBER *q, long width)
649 long numdigits, dendigits, digits;
650 long width1, width2;
651 long n, k;
653 if (width < 8)
654 width = 8;
655 numdigits = zdigits(q->num);
656 n = numdigits;
657 k = 0;
658 while (++k, n)
659 n /= 10;
660 if (qisint(q)) {
661 width -= k;
662 k = 16 - k;
663 if (k < 2)
664 k = 2;
665 PRINTF1("(%ld)", numdigits);
666 while (k-- > 0)
667 PUTCHAR(' ');
668 fitzprint(q->num, numdigits, width);
669 return;
671 dendigits = zdigits(q->den);
672 PRINTF2("(%ld/%ld)", numdigits, dendigits);
673 digits = numdigits + dendigits;
674 n = dendigits;
675 while (++k, n)
676 n /= 10;
677 width -= k;
678 k = 16 - k;
679 if (k < 2)
680 k = 2;
681 while (k-- > 0)
682 PUTCHAR(' ');
683 if (digits <= width) {
684 qprintf("%r", q);
685 return;
687 width1 = (width * numdigits)/digits;
688 if (width1 < 8)
689 width1 = 8;
690 width2 = width - width1;
691 if (width2 < 8) {
692 width2 = 8;
693 width1 = width - width2;
695 fitzprint(q->num, numdigits, width1);
696 PUTCHAR('/');
697 fitzprint(q->den, dendigits, width2);