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/
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
55 qprintf(char *fmt
, ...)
60 long width
= 0, precision
= 0;
64 while ((ch
= *fmt
++) != '\0') {
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;
87 width
= 0; precision
= 8; sign
= 1;
93 q
= va_arg(ap
, NUMBER
*);
97 q
= va_arg(ap
, NUMBER
*);
98 qprintff(q
, width
, precision
);
101 q
= va_arg(ap
, NUMBER
*);
102 qprintfe(q
, width
, precision
);
106 q
= va_arg(ap
, NUMBER
*);
107 qprintfr(q
, width
, (BOOL
) (ch
== 'R'));
110 q
= va_arg(ap
, NUMBER
*);
111 zprintval(q
->num
, 0L, width
);
114 q
= va_arg(ap
, NUMBER
*);
115 zprintval(q
->den
, 0L, width
);
118 q
= va_arg(ap
, NUMBER
*);
122 q
= va_arg(ap
, NUMBER
*);
126 q
= va_arg(ap
, NUMBER
*);
130 PUTSTR(va_arg(ap
, char *));
133 PUTCHAR(va_arg(ap
, int));
142 if (('0' <= ch
&& ch
<= '9') ||
143 ch
== '.' || ch
== '*') {
145 q
= va_arg(ap
, NUMBER
*);
146 width
= sign
* qtoi(q
);
148 } else if (ch
!= '.') {
150 while ('0' <= (ch
= *fmt
++) &&
152 width
= width
* 10 + ch
- '0';
156 if ((ch
= *fmt
++) == '*') {
157 q
= va_arg(ap
, NUMBER
*);
162 while ('0' <= (ch
= *fmt
++) &&
164 precision
*= 10+ch
-'0';
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.
181 qprintnum(NUMBER
*q
, int outmode
)
185 int outmode2
= MODE2_OFF
;
187 if (outmode
== MODE_DEFAULT
) {
188 outmode
= conf
->outmode
;
189 outmode2
= conf
->outmode2
;
193 if (conf
->tilde_ok
&& qisfrac(q
))
199 prec
= qdecplaces(q
);
200 if ((prec
< 0) || (prec
> conf
->outdigits
)) {
204 if (conf
->fullzero
|| (prec
< 0) ||
205 (prec
> conf
->outdigits
))
206 prec
= conf
->outdigits
;
207 qprintff(q
, 0L, prec
);
211 qprintfr(q
, 0L, FALSE
);
221 exp
= qilog10(&tmpval
);
222 if (exp
== 0) { /* in range to output as real */
223 qprintnum(q
, MODE_REAL
);
229 ztenpow(exp
, &tmpval
.den
);
231 ztenpow(-exp
, &tmpval
.num
);
232 q
= qmul(q
, &tmpval
);
235 qprintnum(q
, MODE_REAL
);
237 PRINTF1("e%ld", exp
);
253 math_error("Bad mode for print");
257 if (outmode2
!= MODE2_OFF
) {
259 qprintnum(q
, outmode2
);
266 * Print a number in floating point representation.
270 qprintff(NUMBER
*q
, long width
, long precision
)
274 if (precision
!= scalefactor
) {
277 ztenpow(precision
, &scalenumber
);
278 scalefactor
= precision
;
281 zmul(q
->num
, scalenumber
, &z
);
285 zquo(z
, q
->den
, &z1
, conf
->outround
);
290 if (qisneg(q
) && ziszero(z
))
292 zprintval(z
, precision
, width
);
299 * Print a number in exponential notation.
304 qprintfe(NUMBER
*q
, long UNUSED width
, long precision
)
308 ZVALUE num
, zden
, tenpow
, tmp
;
317 exponent
= zdigits(num
) - zdigits(zden
);
319 ztenpow(exponent
, &tenpow
);
320 zmul(zden
, tenpow
, &tmp
);
325 ztenpow(-exponent
, &tenpow
);
326 zmul(num
, tenpow
, &tmp
);
330 if (zrel(num
, zden
) < 0) {
331 zmuli(num
, 10L, &tmp
);
332 if (num
.v
!= q
->num
.v
)
339 q2
.num
.sign
= q
->num
.sign
;
340 qprintff(&q2
, 0L, precision
);
342 PRINTF1("e%ld", exponent
);
343 if (num
.v
!= q
->num
.v
)
345 if (zden
.v
!= q
->den
.v
)
351 * Print a number in rational representation.
355 qprintfr(NUMBER
*q
, long width
, BOOL force
)
357 zprintval(q
->num
, 0L, width
);
358 if (force
|| qisfrac(q
)) {
360 zprintval(q
->den
, 0L, width
);
366 * Print a number as an integer (truncating fractional part).
370 qprintfd(NUMBER
*q
, long width
)
375 zquo(q
->num
, q
->den
, &z
, conf
->outround
);
376 zprintval(z
, 0L, width
);
379 zprintval(q
->num
, 0L, width
);
385 * Print a number in hex.
386 * This prints the numerator and denominator in hex.
389 qprintfx(NUMBER
*q
, long width
)
391 zprintx(q
->num
, width
);
400 * Print a number in binary.
401 * This prints the numerator and denominator in binary.
404 qprintfb(NUMBER
*q
, long width
)
406 zprintb(q
->num
, width
);
415 * Print a number in octal.
416 * This prints the numerator and denominator in octal.
419 qprintfo(NUMBER
*q
, long width
)
421 zprinto(q
->num
, width
);
430 * Convert a string to a number in rational, floating point,
431 * exponential notation, hex, or octal.
439 ZVALUE div
, newnum
, newden
, tmp
;
449 if ((*t
== '+') || (*t
== '-'))
451 if ((*t
== '0') && ((t
[1] == 'x') || (t
[1] == 'X'))) {
455 while (((*t
>= '0') && (*t
<= '9')) || (hex
&&
456 (((*t
>= 'a') && (*t
<= 'f')) || ((*t
>= 'A') && (*t
<= 'F')))))
461 } else if ((*t
== '.') || (*t
== 'e') || (*t
== 'E')) {
464 while ((*t
>= '0') && (*t
<= '9')) {
470 * Parse exponent if any
472 if ((*t
== 'e') || (*t
== 'E')) {
476 else if (*t
== '-') {
480 while ((*t
>= '0') && (*t
<= '9')) {
481 exp
= (exp
* 10) + *t
++ - '0';
482 if (exp
> (MAXLONG
/10L)) {
483 math_error("Exponent too large");
488 ztenpow(decimals
, &q
->den
);
493 return qlink(&_qzero_
);
496 * Apply the exponential if any
501 zmul(q
->den
, tmp
, &newden
);
505 zmul(q
->num
, tmp
, &newnum
);
512 * Reduce the fraction to lowest terms
514 if (!zisunit(q
->num
) && !zisunit(q
->den
)) {
515 zgcd(q
->num
, q
->den
, &div
);
517 zequo(q
->num
, div
, &newnum
);
519 zequo(q
->den
, div
, &newden
);
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.
541 qparse(char *cp
, int flags
)
546 if ((*cp
== '+') || (*cp
== '-'))
548 if ((*cp
== '+') || (*cp
== '-'))
552 if ((*cp
== '0') && ((cp
[1] == 'x') || (cp
[1] == 'X'))) {
554 while (((*cp
>= '0') && (*cp
<= '9')) ||
555 ((*cp
>= 'a') && (*cp
<= 'f')) ||
556 ((*cp
>= 'A') && (*cp
<= 'F')))
558 if (((*cp
== 'i') || (*cp
== 'I')) && (flags
& QPF_IMAG
))
560 if ((*cp
== '.') || ((*cp
== '/') && (flags
& QPF_SLASH
)) ||
561 ((*cp
>= '0') && (*cp
<= '9')) ||
562 ((*cp
>= 'a') && (*cp
<= 'z')) ||
563 ((*cp
>= 'A') && (*cp
<= 'Z')))
569 if ((*cp
== '0') && ((cp
[1] == 'b') || (cp
[1] == 'B'))) {
571 while ((*cp
== '0') || (*cp
== '1'))
573 if (((*cp
== 'i') || (*cp
== 'I')) && (flags
& QPF_IMAG
))
575 if ((*cp
== '.') || ((*cp
== '/') && (flags
& QPF_SLASH
)) ||
576 ((*cp
>= '0') && (*cp
<= '9')) ||
577 ((*cp
>= 'a') && (*cp
<= 'z')) ||
578 ((*cp
>= 'A') && (*cp
<= 'Z')))
584 if ((*cp
== '0') && (cp
[1] >= '0') && (cp
[1] <= '9')) {
585 while ((*cp
>= '0') && (*cp
<= '7'))
587 if (((*cp
== 'i') || (*cp
== 'I')) && (flags
& QPF_IMAG
))
589 if ((*cp
== '.') || ((*cp
== '/') && (flags
& QPF_SLASH
)) ||
590 ((*cp
>= '0') && (*cp
<= '9')) ||
591 ((*cp
>= 'a') && (*cp
<= 'z')) ||
592 ((*cp
>= 'A') && (*cp
<= 'Z')))
598 * Number is decimal but can still be a fraction or real or exponential
600 while ((*cp
>= '0') && (*cp
<= '9'))
602 if (*cp
== '/' && flags
& QPF_SLASH
) { /* fraction */
604 while ((*cp
>= '0') && (*cp
<= '9'))
606 if (((*cp
== 'i') || (*cp
== 'I')) && (flags
& QPF_IMAG
))
608 if ((*cp
== '.') || ((*cp
== '/') && (flags
& QPF_SLASH
)) ||
609 ((*cp
>= '0') && (*cp
<= '9')) ||
610 ((*cp
>= 'a') && (*cp
<= 'z')) ||
611 ((*cp
>= 'A') && (*cp
<= 'Z')))
615 if (*cp
== '.') { /* floating point */
617 while ((*cp
>= '0') && (*cp
<= '9'))
620 if ((*cp
== 'e') || (*cp
== 'E')) { /* exponential */
622 if ((*cp
== '+') || (*cp
== '-'))
624 if ((*cp
== '+') || (*cp
== '-'))
626 while ((*cp
>= '0') && (*cp
<= '9'))
630 if (((*cp
== 'i') || (*cp
== 'I')) && (flags
& QPF_IMAG
))
632 if ((*cp
== '.') || ((*cp
== '/') && (flags
& QPF_SLASH
)) ||
633 ((*cp
>= '0') && (*cp
<= '9')) ||
634 ((*cp
>= 'a') && (*cp
<= 'z')) ||
635 ((*cp
>= 'A') && (*cp
<= 'Z')))
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.
647 fitprint(NUMBER
*q
, long width
)
649 long numdigits
, dendigits
, digits
;
655 numdigits
= zdigits(q
->num
);
665 PRINTF1("(%ld)", numdigits
);
668 fitzprint(q
->num
, numdigits
, width
);
671 dendigits
= zdigits(q
->den
);
672 PRINTF2("(%ld/%ld)", numdigits
, dendigits
);
673 digits
= numdigits
+ dendigits
;
683 if (digits
<= width
) {
687 width1
= (width
* numdigits
)/digits
;
690 width2
= width
- width1
;
693 width1
= width
- width2
;
695 fitzprint(q
->num
, numdigits
, width1
);
697 fitzprint(q
->den
, dendigits
, width2
);