home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume27
/
calc-2.9.0
/
part08
< prev
next >
Wrap
Text File
|
1993-12-07
|
60KB
|
2,761 lines
Newsgroups: comp.sources.unix
From: dbell@canb.auug.org.au (David I. Bell)
Subject: v27i135: calc-2.9.0 - arbitrary precision C-like programmable calculator, Part08/19
References: <1.755316719.21314@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com
Submitted-By: dbell@canb.auug.org.au (David I. Bell)
Posting-Number: Volume 27, Issue 135
Archive-Name: calc-2.9.0/part08
#!/bin/sh
# this is part 8 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file calc2.9.0/opcodes.c continued
#
CurArch=8
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file calc2.9.0/opcodes.c"
sed 's/^X//' << 'SHAR_EOF' >> calc2.9.0/opcodes.c
X#endif
X vsprintf(buf, fmt, ap);
X va_end(ap);
X fprintf(stderr, "%s\n", buf);
X funcname = NULL;
X longjmp(jmpbuf, 1);
X}
X
X/* END CODE */
SHAR_EOF
echo "File calc2.9.0/opcodes.c is complete"
chmod 0644 calc2.9.0/opcodes.c || echo "restore of calc2.9.0/opcodes.c fails"
set `wc -c calc2.9.0/opcodes.c`;Sum=$1
if test "$Sum" != "52101"
then echo original size 52101, current size $Sum;fi
echo "x - extracting calc2.9.0/opcodes.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/opcodes.h &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
X
X#ifndef OPCODES_H
X#define OPCODES_H
X
X
X/*
X * Opcodes
X */
X#define OP_NOP 0L /* no operation */
X#define OP_LOCALADDR 1L /* load address of local variable */
X#define OP_GLOBALADDR 2L /* load address of global variable */
X#define OP_PARAMADDR 3L /* load address of paramater variable */
X#define OP_LOCALVALUE 4L /* load value of local variable */
X#define OP_GLOBALVALUE 5L /* load value of global variable */
X#define OP_PARAMVALUE 6L /* load value of paramater variable */
X#define OP_NUMBER 7L /* load constant real numeric value */
X#define OP_INDEXADDR 8L /* load array index address */
X#define OP_PRINTRESULT 9L /* print result of top-level expression */
X#define OP_ASSIGN 10L /* assign value to variable */
X#define OP_ADD 11L /* add top two values */
X#define OP_SUB 12L /* subtract top two values */
X#define OP_MUL 13L /* multiply top two values */
X#define OP_DIV 14L /* divide top two values */
X#define OP_MOD 15L /* take mod of top two values */
X#define OP_SAVE 16L /* save value for later use */
X#define OP_NEGATE 17L /* negate top value */
X#define OP_INVERT 18L /* invert top value */
X#define OP_INT 19L /* take integer part of top value */
X#define OP_FRAC 20L /* take fraction part of top value */
X#define OP_NUMERATOR 21L /* take numerator of top value */
X#define OP_DENOMINATOR 22L /* take denominator of top value */
X#define OP_DUPLICATE 23L /* duplicate top value on stack */
X#define OP_POP 24L /* pop top value from stack */
X#define OP_RETURN 25L /* return value of function */
X#define OP_JUMPEQ 26L /* jump if top value is zero */
X#define OP_JUMPNE 27L /* jump if top value is nonzero */
X#define OP_JUMP 28L /* jump unconditionally */
X#define OP_USERCALL 29L /* call a user-defined function */
X#define OP_GETVALUE 30L /* convert address to value */
X#define OP_EQ 31L /* test top two elements for equality */
X#define OP_NE 32L /* test top two elements for inequality */
X#define OP_LE 33L /* test top two elements for <= */
X#define OP_GE 34L /* test top two elements for >= */
X#define OP_LT 35L /* test top two elements for < */
X#define OP_GT 36L /* test top two elements for > */
X#define OP_PREINC 37L /* add one to variable (++x) */
X#define OP_PREDEC 38L /* subtract one from variable (--x) */
X#define OP_POSTINC 39L /* add one to variable (x++) */
X#define OP_POSTDEC 40L /* subtract one from variable (x--) */
X#define OP_DEBUG 41L /* debugging point */
X#define OP_PRINT 42L /* print value */
X#define OP_ASSIGNPOP 43L /* assign to variable and remove it */
X#define OP_ZERO 44L /* put zero on the stack */
X#define OP_ONE 45L /* put one on the stack */
X#define OP_PRINTEOL 46L /* print end of line */
X#define OP_PRINTSPACE 47L /* print a space */
X#define OP_PRINTSTRING 48L /* print constant string */
X#define OP_DUPVALUE 49L /* duplicate value of top value */
X#define OP_OLDVALUE 50L /* old calculation value */
X#define OP_QUO 51L /* integer quotient of top two values */
X#define OP_POWER 52L /* number raised to a power */
X#define OP_QUIT 53L /* quit program */
X#define OP_CALL 54L /* call built-in routine */
X#define OP_GETEPSILON 55L /* get allowed error for calculations */
X#define OP_AND 56L /* arithmetic and */
X#define OP_OR 57L /* arithmetic or */
X#define OP_NOT 58L /* logical not */
X#define OP_ABS 59L /* absolute value */
X#define OP_SGN 60L /* sign of number */
X#define OP_ISINT 61L /* whether top value is integer */
X#define OP_CONDORJUMP 62L /* conditional or jump */
X#define OP_CONDANDJUMP 63L /* conditional and jump */
X#define OP_SQUARE 64L /* square top value */
X#define OP_STRING 65L /* load constant string value */
X#define OP_ISNUM 66L /* whether top value is a number */
X#define OP_UNDEF 67L /* load undefined value on stack */
X#define OP_ISNULL 68L /* whether variable is the null value */
X#define OP_ARGVALUE 69L /* load value of argument (parameter) n */
X#define OP_MATCREATE 70L /* create matrix */
X#define OP_ISMAT 71L /* whether variable is a matrix */
X#define OP_ISSTR 72L /* whether variable is a string */
X#define OP_GETCONFIG 73L /* get value of configuration parameter */
X#define OP_LEFTSHIFT 74L /* left shift of integer */
X#define OP_RIGHTSHIFT 75L /* right shift of integer */
X#define OP_CASEJUMP 76L /* test case and jump if not matched */
X#define OP_ISODD 77L /* whether value is an odd integer */
X#define OP_ISEVEN 78L /* whether value is even integer */
X#define OP_FIADDR 79L /* 'fast index' matrix value address */
X#define OP_FIVALUE 80L /* 'fast index' matrix value */
X#define OP_ISREAL 81L /* test value for real number */
X#define OP_IMAGINARY 82L /* load imaginary numeric constant */
X#define OP_RE 83L /* real part of complex number */
X#define OP_IM 84L /* imaginary part of complex number */
X#define OP_CONJUGATE 85L /* complex conjugate of complex number */
X#define OP_OBJCREATE 86L /* create object */
X#define OP_ISOBJ 87L /* whether value is an object */
X#define OP_NORM 88L /* norm of value (square of abs) */
X#define OP_ELEMADDR 89L /* address of element of object */
X#define OP_ELEMVALUE 90L /* value of element of object */
X#define OP_ISTYPE 91L /* whether two values are the same type */
X#define OP_SCALE 92L /* scale value by a power of two */
X#define OP_ISLIST 93L /* whether value is a list */
X#define OP_SWAP 94L /* swap values of two variables */
X#define OP_ISSIMPLE 95L /* whether value is a simple type */
X#define OP_CMP 96L /* compare values returning -1, 0, or 1 */
X#define OP_QUOMOD 97L /* calculate quotient and remainder */
X#define OP_SETCONFIG 98L /* set configuration parameter */
X#define OP_SETEPSILON 99L /* set allowed error for calculations */
X#define OP_ISFILE 100L /* whether value is a file */
X#define OP_ISASSOC 101L /* whether value is an association */
X#define OP_INITSTATIC 102L /* once only code for static initialization */
X#define OP_ELEMINIT 103L /* assign element of matrix or object */
X#define MAX_OPCODE 103L /* highest legal opcode */
X
X#endif
X
X/* END CODE */
SHAR_EOF
chmod 0644 calc2.9.0/opcodes.h || echo "restore of calc2.9.0/opcodes.h fails"
set `wc -c calc2.9.0/opcodes.h`;Sum=$1
if test "$Sum" != "6052"
then echo original size 6052, current size $Sum;fi
echo "x - extracting calc2.9.0/qfunc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/qfunc.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X *
X * Extended precision rational arithmetic non-primitive functions
X */
X
X#include "qmath.h"
X
X
XNUMBER *_epsilon_; /* default precision for real functions */
Xlong _epsilonprec_; /* bits of precision for epsilon */
X
X
X/*
X * Set the default precision for real calculations.
X * The precision must be between zero and one.
X */
Xvoid
Xsetepsilon(q)
X NUMBER *q; /* number to be set as the new epsilon */
X{
X NUMBER *old;
X
X if (qisneg(q) || qiszero(q) || (qreli(q, 1L) >= 0))
X math_error("Epsilon value must be between zero and one");
X old = _epsilon_;
X _epsilonprec_ = qprecision(q);
X _epsilon_ = qlink(q);
X if (old)
X qfree(old);
X}
X
X
X/*
X * Return the inverse of one number modulo another.
X * That is, find x such that:
X * Ax = 1 (mod B)
X * Returns zero if the numbers are not relatively prime (temporary hack).
X */
XNUMBER *
Xqminv(q1, q2)
X NUMBER *q1, *q2;
X{
X NUMBER *r;
X
X if (qisfrac(q1) || qisfrac(q2))
X math_error("Non-integers for minv");
X r = qalloc();
X if (zmodinv(q1->num, q2->num, &r->num)) {
X qfree(r);
X return qlink(&_qzero_);
X }
X return r;
X}
X
X
X/*
X * Return the modulo of one number raised to another.
X * Here q1 is the number to be raised, q2 is the power to raise it to,
X * and q3 is the number to take the modulo with the result.
X * The second and third numbers are assumed nonnegative.
X * Returned answer is non-negative.
X * q4 = qpowermod(q1, q2, q3);
X */
XNUMBER *
Xqpowermod(q1, q2, q3)
X NUMBER *q1, *q2, *q3;
X{
X NUMBER *r;
X
X if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
X math_error("Non-integers for powermod");
X r = qalloc();
X zpowermod(q1->num, q2->num, q3->num, &r->num);
X return r;
X}
X
X
X/*
X * Return the power function of one number with another.
X * The power must be integral.
X * q3 = qpowi(q1, q2);
X */
XNUMBER *
Xqpowi(q1, q2)
X NUMBER *q1, *q2;
X{
X register NUMBER *r;
X BOOL invert, sign;
X ZVALUE num, den, z2;
X
X if (qisfrac(q2))
X math_error("Raising number to fractional power");
X num = q1->num;
X den = q1->den;
X z2 = q2->num;
X sign = (num.sign && zisodd(z2));
X invert = z2.sign;
X num.sign = 0;
X z2.sign = 0;
X /*
X * Check for trivial cases first.
X */
X if (ziszero(num)) { /* zero raised to a power */
X if (invert || ziszero(z2))
X math_error("Zero raised to non-positive power");
X return qlink(&_qzero_);
X }
X if (zisunit(num) && zisunit(den)) { /* 1 or -1 raised to a power */
X r = (sign ? q1 : &_qone_);
X r->links++;
X return r;
X }
X if (ziszero(z2)) /* raising to zeroth power */
X return qlink(&_qone_);
X if (zisunit(z2)) { /* raising to power 1 or -1 */
X if (invert)
X return qinv(q1);
X return qlink(q1);
X }
X /*
X * Not a trivial case. Do the real work.
X */
X r = qalloc();
X if (!zisunit(num))
X zpowi(num, z2, &r->num);
X if (!zisunit(den))
X zpowi(den, z2, &r->den);
X if (invert) {
X z2 = r->num;
X r->num = r->den;
X r->den = z2;
X }
X r->num.sign = sign;
X return r;
X}
X
X
X/*
X * Given the legs of a right triangle, compute its hypothenuse within
X * the specified error. This is sqrt(a^2 + b^2).
X */
XNUMBER *
Xqhypot(q1, q2, epsilon)
X NUMBER *q1, *q2, *epsilon;
X{
X NUMBER *tmp1, *tmp2, *tmp3;
X
X if (qisneg(epsilon) || qiszero(epsilon))
X math_error("Bad epsilon value for hypot");
X if (qiszero(q1))
X return qabs(q2);
X if (qiszero(q2))
X return qabs(q1);
X tmp1 = qsquare(q1);
X tmp2 = qsquare(q2);
X tmp3 = qadd(tmp1, tmp2);
X qfree(tmp1);
X qfree(tmp2);
X tmp1 = qsqrt(tmp3, epsilon);
X qfree(tmp3);
X return tmp1;
X}
X
X
X/*
X * Given one leg of a right triangle with unit hypothenuse, calculate
X * the other leg within the specified error. This is sqrt(1 - a^2).
X * If the wantneg flag is nonzero, then negative square root is returned.
X */
XNUMBER *
Xqlegtoleg(q, epsilon, wantneg)
X NUMBER *q, *epsilon;
X BOOL wantneg;
X{
X NUMBER *qt, *res, qtmp;
X ZVALUE num, ztmp1, ztmp2;
X
X if (qisneg(epsilon) || qiszero(epsilon))
X math_error("Bad epsilon value for legtoleg");
X if (qisunit(q))
X return qlink(&_qzero_);
X if (qiszero(q)) {
X if (wantneg)
X return qlink(&_qnegone_);
X return qlink(&_qone_);
X }
X num = q->num;
X num.sign = 0;
X if (zrel(num, q->den) >= 0)
X math_error("Leg too large in legtoleg");
X zsquare(q->den, &ztmp1);
X zsquare(num, &ztmp2);
X zsub(ztmp1, ztmp2, &qtmp.num);
X zfree(ztmp1);
X zfree(ztmp2);
X qtmp.den = _one_;
X qt = qsqrt(&qtmp, epsilon);
X zfree(qtmp.num);
X qtmp.num = q->den;
X res = qdiv(qt, &qtmp);
X qfree(qt);
X qt = qbappr(res, epsilon);
X qfree(res);
X if (wantneg) {
X res = qneg(qt);
X qfree(qt);
X qt = res;
X }
X return qt;
X}
X
X
X/*
X * Compute the square root of a number to within the specified error.
X * If the number is an exact square, the exact result is returned.
X * q3 = qsqrt(q1, q2);
X */
XNUMBER *
Xqsqrt(q1, epsilon)
X register NUMBER *q1, *epsilon;
X{
X long bits, bits2; /* number of bits of precision */
X int exact;
X NUMBER *r;
X ZVALUE t1, t2;
X
X if (qisneg(q1))
X math_error("Square root of negative number");
X if (qisneg(epsilon) || qiszero(epsilon))
X math_error("Bad epsilon value for sqrt");
X if (qiszero(q1))
X return qlink(&_qzero_);
X if (qisunit(q1))
X return qlink(&_qone_);
X if (qiszero(epsilon) && qisint(q1) && zistiny(q1->num) && (*q1->num.v <= 3))
X return qlink(&_qone_);
X bits = zhighbit(epsilon->den) - zhighbit(epsilon->num) + 1;
X if (bits < 0)
X bits = 0;
X bits2 = zhighbit(q1->num) - zhighbit(q1->den) + 1;
X if (bits2 > 0)
X bits += bits2;
X r = qalloc();
X zshift(q1->num, bits * 2, &t2);
X zmul(q1->den, t2, &t1);
X zfree(t2);
X exact = zsqrt(t1, &t2);
X zfree(t1);
X if (exact) {
X zshift(q1->den, bits, &t1);
X zreduce(t2, t1, &r->num, &r->den);
X } else {
X zquo(t2, q1->den, &t1);
X zfree(t2);
X zbitvalue(bits, &t2);
X zreduce(t1, t2, &r->num, &r->den);
X }
X zfree(t1);
X zfree(t2);
X if (qiszero(r)) {
X qfree(r);
X r = qlink(&_qzero_);
X }
X return r;
X}
X
X
X/*
X * Calculate the integral part of the square root of a number.
X * Example: qisqrt(13) = 3.
X */
XNUMBER *
Xqisqrt(q)
X NUMBER *q;
X{
X NUMBER *r;
X ZVALUE tmp;
X
X if (qisneg(q))
X math_error("Square root of negative number");
X if (qiszero(q))
X return qlink(&_qzero_);
X if (qisint(q) && zistiny(q->num) && (z1tol(q->num) < 4))
X return qlink(&_qone_);
X r = qalloc();
X if (qisint(q)) {
X (void) zsqrt(q->num, &r->num);
X return r;
X }
X zquo(q->num, q->den, &tmp);
X (void) zsqrt(tmp, &r->num);
X zfree(tmp);
X return r;
X}
X
X
X/*
X * Return whether or not a number is an exact square.
X */
XBOOL
Xqissquare(q)
X NUMBER *q;
X{
X BOOL flag;
X
X flag = zissquare(q->num);
X if (qisint(q) || !flag)
X return flag;
X return zissquare(q->den);
X}
X
X
X/*
X * Compute the greatest integer of the Kth root of a number.
X * Example: qiroot(85, 3) = 4.
X */
XNUMBER *
Xqiroot(q1, q2)
X register NUMBER *q1, *q2;
X{
X NUMBER *r;
X ZVALUE tmp;
X
X if (qisneg(q2) || qiszero(q2) || qisfrac(q2))
X math_error("Taking number to bad root value");
X if (qiszero(q1))
X return qlink(&_qzero_);
X if (qisone(q1) || qisone(q2))
X return qlink(q1);
X if (qistwo(q2))
X return qisqrt(q1);
X r = qalloc();
X if (qisint(q1)) {
X zroot(q1->num, q2->num, &r->num);
X return r;
X }
X zquo(q1->num, q1->den, &tmp);
X zroot(tmp, q2->num, &r->num);
X zfree(tmp);
X return r;
X}
X
X
X/*
X * Return the greatest integer of the base 2 log of a number.
X * This is the number such that 1 <= x / log2(x) < 2.
X * Examples: qilog2(8) = 3, qilog2(1.3) = 1, qilog2(1/7) = -3.
X */
Xlong
Xqilog2(q)
X NUMBER *q; /* number to take log of */
X{
X long n; /* power of two */
X int c; /* result of comparison */
X ZVALUE tmp; /* temporary value */
X
X if (qisneg(q) || qiszero(q))
X math_error("Non-positive number for log2");
X if (qisint(q))
X return zhighbit(q->num);
X n = zhighbit(q->num) - zhighbit(q->den);
X if (n == 0)
X c = zrel(q->num, q->den);
X else if (n > 0) {
X zshift(q->den, n, &tmp);
X c = zrel(q->num, tmp);
X } else {
X zshift(q->num, n, &tmp);
X c = zrel(tmp, q->den);
X }
X if (n)
X zfree(tmp);
X if (c < 0)
X n--;
X return n;
X}
X
X
X/*
X * Return the greatest integer of the base 10 log of a number.
X * This is the number such that 1 <= x / log10(x) < 10.
X * Examples: qilog10(100) = 2, qilog10(12.3) = 1, qilog10(.023) = -2.
X */
Xlong
Xqilog10(q)
X NUMBER *q; /* number to take log of */
X{
X long n; /* log value */
X ZVALUE temp; /* temporary value */
X
X if (qisneg(q) || qiszero(q))
X math_error("Non-positive number for log10");
X if (qisint(q))
X return zlog10(q->num);
X /*
X * The number is not an integer.
X * Compute the result if the number is greater than one.
X */
X if ((q->num.len > q->den.len) ||
X ((q->num.len == q->den.len) && (zrel(q->num, q->den) > 0))) {
X zquo(q->num, q->den, &temp);
X n = zlog10(temp);
X zfree(temp);
X return n;
X }
X /*
X * Here if the number is less than one.
X * If the number is the inverse of a power of ten, then the obvious answer
X * will be off by one. Subtracting one if the number is the inverse of an
X * integer will fix it.
X */
X if (zisunit(q->num))
X zsub(q->den, _one_, &temp);
X else
X zquo(q->den, q->num, &temp);
X n = -zlog10(temp) - 1;
X zfree(temp);
X return n;
X}
X
X
X/*
X * Return the number of digits in a number, ignoring the sign.
X * For fractions, this is the number of digits of its greatest integer.
X * Examples: qdigits(3456) = 4, qdigits(-23.45) = 2, qdigits(.0120) = 1.
X */
Xlong
Xqdigits(q)
X NUMBER *q; /* number to count digits of */
X{
X long n; /* number of digits */
X ZVALUE temp; /* temporary value */
X
X if (qisint(q))
X return zdigits(q->num);
X zquo(q->num, q->den, &temp);
X n = zdigits(temp);
X zfree(temp);
X return n;
X}
X
X
X/*
X * Return the digit at the specified decimal place of a number represented
X * in floating point. The lowest digit of the integral part of a number
X * is the zeroth decimal place. Negative decimal places indicate digits
X * to the right of the decimal point. Examples: qdigit(1234.5678, 1) = 3,
X * qdigit(1234.5678, -3) = 7.
X */
XFLAG
Xqdigit(q, n)
X NUMBER *q;
X long n;
X{
X ZVALUE tenpow, tmp1, tmp2;
X FLAG res;
X
X /*
X * Zero number or negative decimal place of integer is trivial.
X */
X if (qiszero(q) || (qisint(q) && (n < 0)))
X return 0;
X /*
X * For non-negative decimal places, answer is easy.
X */
X if (n >= 0) {
X if (qisint(q))
X return zdigit(q->num, n);
X zquo(q->num, q->den, &tmp1);
X res = zdigit(tmp1, n);
X zfree(tmp1);
X return res;
X }
X /*
X * Fractional value and want negative digit, must work harder.
X */
X ztenpow(-n, &tenpow);
X zmul(q->num, tenpow, &tmp1);
X zfree(tenpow);
X zquo(tmp1, q->den, &tmp2);
X res = zmodi(tmp2, 10L);
X zfree(tmp1);
X zfree(tmp2);
X return res;
X}
X
X
X/*
X * Return whether or not a bit is set at the specified bit position in a
X * number. The lowest bit of the integral part of a number is the zeroth
X * bit position. Negative bit positions indicate bits to the right of the
X * binary decimal point. Examples: qdigit(17.1, 0) = 1, qdigit(17.1, -1) = 0.
X */
XBOOL
Xqisset(q, n)
X NUMBER *q;
X long n;
X{
X NUMBER *qtmp1, *qtmp2;
X ZVALUE ztmp;
X BOOL res;
X
X /*
X * Zero number or negative bit position place of integer is trivial.
X */
X if (qiszero(q) || (qisint(q) && (n < 0)))
X return FALSE;
X /*
X * For non-negative bit positions, answer is easy.
X */
X if (n >= 0) {
X if (qisint(q))
X return zisset(q->num, n);
X zquo(q->num, q->den, &ztmp);
X res = zisset(ztmp, n);
X zfree(ztmp);
X return res;
X }
X /*
X * Fractional value and want negative bit position, must work harder.
X */
X qtmp1 = qscale(q, -n);
X qtmp2 = qint(qtmp1);
X qfree(qtmp1);
X res = ((qtmp2->num.v[0] & 0x01) != 0);
X qfree(qtmp2);
X return res;
X}
X
X
X/*
X * Compute the factorial of an integer.
X * q2 = qfact(q1);
X */
XNUMBER *
Xqfact(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (qisfrac(q))
X math_error("Non-integral factorial");
X if (qiszero(q) || zisone(q->num))
X return qlink(&_qone_);
X r = qalloc();
X zfact(q->num, &r->num);
X return r;
X}
X
X
X/*
X * Compute the product of the primes less than or equal to a number.
X * q2 = qpfact(q1);
X */
XNUMBER *
Xqpfact(q)
X register NUMBER *q;
X{
X NUMBER *r;
X
X if (qisfrac(q))
X math_error("Non-integral factorial");
X r = qalloc();
X zpfact(q->num, &r->num);
X return r;
X}
X
X
X/*
X * Compute the lcm of all the numbers less than or equal to a number.
X * q2 = qlcmfact(q1);
X */
XNUMBER *
Xqlcmfact(q)
X register NUMBER *q;
X{
X NUMBER *r;
X
X if (qisfrac(q))
X math_error("Non-integral lcmfact");
X r = qalloc();
X zlcmfact(q->num, &r->num);
X return r;
X}
X
X
X/*
X * Compute the permutation function M! / (M - N)!.
X */
XNUMBER *
Xqperm(q1, q2)
X register NUMBER *q1, *q2;
X{
X register NUMBER *r;
X
X if (qisfrac(q1) || qisfrac(q2))
X math_error("Non-integral arguments for permutation");
X r = qalloc();
X zperm(q1->num, q2->num, &r->num);
X return r;
X}
X
X
X/*
X * Compute the combinatorial function M! / (N! * (M - N)!).
X */
XNUMBER *
Xqcomb(q1, q2)
X register NUMBER *q1, *q2;
X{
X register NUMBER *r;
X
X if (qisfrac(q1) || qisfrac(q2))
X math_error("Non-integral arguments for combinatorial");
X r = qalloc();
X zcomb(q1->num, q2->num, &r->num);
X return r;
X}
X
X
X/*
X * Compute the Jacobi function (a / b).
X * -1 => a is not quadratic residue mod b
X * 1 => b is composite, or a is quad residue of b
X * 0 => b is even or b < 0
X */
XNUMBER *
Xqjacobi(q1, q2)
X register NUMBER *q1, *q2;
X{
X if (qisfrac(q1) || qisfrac(q2))
X math_error("Non-integral arguments for jacobi");
X return itoq((long) zjacobi(q1->num, q2->num));
X}
X
X
X/*
X * Compute the Fibonacci number F(n).
X */
XNUMBER *
Xqfib(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (qisfrac(q))
X math_error("Non-integral Fibonacci number");
X r = qalloc();
X zfib(q->num, &r->num);
X return r;
X}
X
X
X/*
X * Truncate a number to the specified number of decimal places.
X * Specifying zero places makes the result identical to qint.
X * Example: qtrunc(2/3, 3) = .666
X */
XNUMBER *
Xqtrunc(q1, q2)
X NUMBER *q1, *q2;
X{
X long places;
X NUMBER *r;
X ZVALUE tenpow, tmp1, tmp2;
X
X if (qisfrac(q2) || qisneg(q2) || !zistiny(q2->num))
X math_error("Bad number of places for qtrunc");
X if (qisint(q1))
X return qlink(q1);
X r = qalloc();
X places = z1tol(q2->num);
X /*
X * Ok, produce the result.
X * First see if we want no places, in which case just take integer part.
X */
X if (places == 0) {
X zquo(q1->num, q1->den, &r->num);
X return r;
X }
X ztenpow(places, &tenpow);
X zmul(q1->num, tenpow, &tmp1);
X zquo(tmp1, q1->den, &tmp2);
X zfree(tmp1);
X if (ziszero(tmp2)) {
X zfree(tmp2);
X return qlink(&_qzero_);
X }
X /*
X * Now reduce the result to the lowest common denominator.
X */
X zgcd(tmp2, tenpow, &tmp1);
X if (zisunit(tmp1)) {
X zfree(tmp1);
X r->num = tmp2;
X r->den = tenpow;
X return r;
X }
X zquo(tmp2, tmp1, &r->num);
X zquo(tenpow, tmp1, &r->den);
X zfree(tmp1);
X zfree(tmp2);
X zfree(tenpow);
X return r;
X}
X
X
X/*
X * Round a number to the specified number of decimal places.
X * Zero decimal places means round to the nearest integer.
X * Example: qround(2/3, 3) = .667
X */
XNUMBER *
Xqround(q, places)
X NUMBER *q; /* number to be rounded */
X long places; /* number of decimal places to round to */
X{
X NUMBER *r;
X ZVALUE tenpow, roundval, tmp1, tmp2;
X
X if (places < 0)
X math_error("Negative places for qround");
X if (qisint(q))
X return qlink(q);
X /*
X * Calculate one half of the denominator, ignoring fractional results.
X * This is the value we will add in order to cause rounding.
X */
X zshift(q->den, -1L, &roundval);
X roundval.sign = q->num.sign;
X /*
X * Ok, now do the actual work to produce the result.
X */
X r = qalloc();
X ztenpow(places, &tenpow);
X zmul(q->num, tenpow, &tmp2);
X zadd(tmp2, roundval, &tmp1);
X zfree(tmp2);
X zfree(roundval);
X zquo(tmp1, q->den, &tmp2);
X zfree(tmp1);
X if (ziszero(tmp2)) {
X zfree(tmp2);
X return qlink(&_qzero_);
X }
X /*
X * Now reduce the result to the lowest common denominator.
X */
X zgcd(tmp2, tenpow, &tmp1);
X if (zisunit(tmp1)) {
X zfree(tmp1);
X r->num = tmp2;
X r->den = tenpow;
X return r;
X }
X zquo(tmp2, tmp1, &r->num);
X zquo(tenpow, tmp1, &r->den);
X zfree(tmp1);
X zfree(tmp2);
X zfree(tenpow);
X return r;
X}
X
X
X/*
X * Truncate a number to the specified number of binary places.
X * Specifying zero places makes the result identical to qint.
X */
XNUMBER *
Xqbtrunc(q1, q2)
X NUMBER *q1, *q2;
X{
X long places, twopow;
X NUMBER *r;
X ZVALUE tmp1, tmp2;
X
X if (qisfrac(q2) || qisneg(q2) || !zistiny(q2->num))
X math_error("Bad number of places for qtrunc");
X if (qisint(q1))
X return qlink(q1);
X r = qalloc();
X places = z1tol(q2->num);
X /*
X * Ok, produce the result.
X * First see if we want no places, in which case just take integer part.
X */
X if (places == 0) {
X zquo(q1->num, q1->den, &r->num);
X return r;
X }
X zshift(q1->num, places, &tmp1);
X zquo(tmp1, q1->den, &tmp2);
X zfree(tmp1);
X if (ziszero(tmp2)) {
X zfree(tmp2);
X return qlink(&_qzero_);
X }
X /*
X * Now reduce the result to the lowest common denominator.
X */
X if (zisodd(tmp2)) {
X r->num = tmp2;
X zbitvalue(places, &r->den);
X return r;
X }
X twopow = zlowbit(tmp2);
X if (twopow > places)
X twopow = places;
X places -= twopow;
X zshift(tmp2, -twopow, &r->num);
X zfree(tmp2);
X zbitvalue(places, &r->den);
X return r;
X}
X
X
X/*
X * Round a number to the specified number of binary places.
X * Zero binary places means round to the nearest integer.
X */
XNUMBER *
Xqbround(q, places)
X NUMBER *q; /* number to be rounded */
X long places; /* number of binary places to round to */
X{
X long twopow;
X NUMBER *r;
X ZVALUE roundval, tmp1, tmp2;
X
X if (places < 0)
X math_error("Negative places for qbround");
X if (qisint(q))
X return qlink(q);
X r = qalloc();
X /*
X * Calculate one half of the denominator, ignoring fractional results.
X * This is the value we will add in order to cause rounding.
X */
X zshift(q->den, -1L, &roundval);
X roundval.sign = q->num.sign;
X /*
X * Ok, produce the result.
X */
X zshift(q->num, places, &tmp1);
X zadd(tmp1, roundval, &tmp2);
X zfree(roundval);
X zfree(tmp1);
X zquo(tmp2, q->den, &tmp1);
X zfree(tmp2);
X if (ziszero(tmp1)) {
X zfree(tmp1);
X return qlink(&_qzero_);
X }
X /*
X * Now reduce the result to the lowest common denominator.
X */
X if (zisodd(tmp1)) {
X r->num = tmp1;
X zbitvalue(places, &r->den);
X return r;
X }
X twopow = zlowbit(tmp1);
X if (twopow > places)
X twopow = places;
X places -= twopow;
X zshift(tmp1, -twopow, &r->num);
X zfree(tmp1);
X zbitvalue(places, &r->den);
X return r;
X}
X
X
X/*
X * Approximate a number by using binary rounding with the minimum number
X * of binary places so that the resulting number is within the specified
X * epsilon of the original number.
X */
XNUMBER *
Xqbappr(q, e)
X NUMBER *q, *e;
X{
X long bits;
X
X if (qisneg(e) || qiszero(e))
X math_error("Bad epsilon value for qbappr");
X if (e == _epsilon_)
X bits = _epsilonprec_ + 1;
X else
X bits = qprecision(e) + 1;
X return qbround(q, bits);
X}
X
X
X/*
X * Approximate a number using continued fractions until the approximation
X * error is less than the specified value. If a NULL pointer is given
X * for the error value, then the closest simpler fraction is returned.
X */
XNUMBER *
Xqcfappr(q, e)
X NUMBER *q, *e;
X{
X NUMBER qtest, *qtmp;
X ZVALUE u1, u2, u3, v1, v2, v3, t1, t2, t3, qq, tt;
X int i;
X BOOL haveeps;
X
X haveeps = TRUE;
X if (e == NULL) {
X haveeps = FALSE;
X e = &_qzero_;
X }
X if (qisneg(e))
X math_error("Negative epsilon for cfappr");
X if (qisint(q) || zisunit(q->num) || (haveeps && qiszero(e)))
X return qlink(q);
X u1 = _one_;
X u2 = _zero_;
X u3 = q->num;
X u3.sign = 0;
X v1 = _zero_;
X v2 = _one_;
X v3 = q->den;
X while (!ziszero(v3)) {
X if (!ziszero(u2) && !ziszero(u1)) {
X qtest.num = u2;
X qtest.den = u1;
X qtest.den.sign = 0;
X qtest.num.sign = q->num.sign;
X qtmp = qsub(q, &qtest);
X qtest = *qtmp;
X qtest.num.sign = 0;
X i = qrel(&qtest, e);
X qfree(qtmp);
X if (i <= 0)
X break;
X }
X zquo(u3, v3, &qq);
X zmul(qq, v1, &tt); zsub(u1, tt, &t1); zfree(tt);
X zmul(qq, v2, &tt); zsub(u2, tt, &t2); zfree(tt);
X zmul(qq, v3, &tt); zsub(u3, tt, &t3); zfree(tt);
X zfree(qq); zfree(u1); zfree(u2);
X if ((u3.v != q->num.v) && (u3.v != q->den.v))
X zfree(u3);
X u1 = v1; u2 = v2; u3 = v3;
X v1 = t1; v2 = t2; v3 = t3;
X }
X if (u3.v != q->den.v)
X zfree(u3);
X zfree(v1);
X zfree(v2);
X i = ziszero(v3);
X zfree(v3);
X if (i && haveeps) {
X zfree(u1);
X zfree(u2);
X return qlink(q);
X }
X qtest.num = u2;
X qtest.den = u1;
X qtest.den.sign = 0;
X qtest.num.sign = q->num.sign;
X qtmp = qcopy(&qtest);
X zfree(u1);
X zfree(u2);
X return qtmp;
X}
X
X
X/*
X * Return an indication on whether or not two fractions are approximately
X * equal within the specified epsilon. Returns negative if the absolute value
X * of the difference between the two numbers is less than epsilon, zero if
X * the difference is equal to epsilon, and positive if the difference is
X * greater than epsilon.
X */
XFLAG
Xqnear(q1, q2, epsilon)
X NUMBER *q1, *q2, *epsilon;
X{
X int res;
X NUMBER qtemp, *qq;
X
X if (qisneg(epsilon))
X math_error("Negative epsilon for near");
X if (q1 == q2) {
X if (qiszero(epsilon))
X return 0;
X return -1;
X }
X if (qiszero(epsilon))
X return qcmp(q1, q2);
X if (qiszero(q2)) {
X qtemp = *q1;
X qtemp.num.sign = 0;
X return qrel(&qtemp, epsilon);
X }
X if (qiszero(q1)) {
X qtemp = *q2;
X qtemp.num.sign = 0;
X return qrel(&qtemp, epsilon);
X }
X qq = qsub(q1, q2);
X qtemp = *qq;
X qtemp.num.sign = 0;
X res = qrel(&qtemp, epsilon);
X qfree(qq);
X return res;
X}
X
X
X/*
X * Compute the gcd (greatest common divisor) of two numbers.
X * q3 = qgcd(q1, q2);
X */
XNUMBER *
Xqgcd(q1, q2)
X register NUMBER *q1, *q2;
X{
X ZVALUE z;
X NUMBER *q;
X
X if (q1 == q2)
X return qabs(q1);
X if (qisfrac(q1) || qisfrac(q2)) {
X q = qalloc();
X zgcd(q1->num, q2->num, &q->num);
X zlcm(q1->den, q2->den, &q->den);
X return q;
X }
X if (qiszero(q1))
X return qabs(q2);
X if (qiszero(q2))
X return qabs(q1);
X if (qisunit(q1) || qisunit(q2))
X return qlink(&_qone_);
X zgcd(q1->num, q2->num, &z);
X if (zisunit(z)) {
X zfree(z);
X return qlink(&_qone_);
X }
X q = qalloc();
X q->num = z;
X return q;
X}
X
X
X/*
X * Compute the lcm (least common multiple) of two numbers.
X * q3 = qlcm(q1, q2);
X */
XNUMBER *
Xqlcm(q1, q2)
X register NUMBER *q1, *q2;
X{
X NUMBER *q;
X
X if (qiszero(q1) || qiszero(q2))
X return qlink(&_qzero_);
X if (q1 == q2)
X return qabs(q1);
X if (qisunit(q1))
X return qabs(q2);
X if (qisunit(q2))
X return qabs(q1);
X q = qalloc();
X zlcm(q1->num, q2->num, &q->num);
X if (qisfrac(q1) || qisfrac(q2))
X zgcd(q1->den, q2->den, &q->den);
X return q;
X}
X
X
X/*
X * Remove all occurances of the specified factor from a number.
X * Returned number is always positive.
X */
XNUMBER *
Xqfacrem(q1, q2)
X NUMBER *q1, *q2;
X{
X long count;
X ZVALUE tmp;
X NUMBER *r;
X
X if (qisfrac(q1) || qisfrac(q2))
X math_error("Non-integers for factor removal");
X count = zfacrem(q1->num, q2->num, &tmp);
X if (zisunit(tmp)) {
X zfree(tmp);
X return qlink(&_qone_);
X }
X if (count == 0) {
X zfree(tmp);
X return qlink(q1);
X }
X r = qalloc();
X r->num = tmp;
X return r;
X}
X
X
X/*
X * Divide one number by the gcd of it with another number repeatedly until
X * the number is relatively prime.
X */
XNUMBER *
Xqgcdrem(q1, q2)
X NUMBER *q1, *q2;
X{
X ZVALUE tmp;
X NUMBER *r;
X
X if (qisfrac(q1) || qisfrac(q2))
X math_error("Non-integers for gcdrem");
X zgcdrem(q1->num, q2->num, &tmp);
X if (zisunit(tmp)) {
X zfree(tmp);
X return qlink(&_qone_);
X }
X if (zcmp(q1->num, tmp) == 0) {
X zfree(tmp);
X return qlink(q1);
X }
X r = qalloc();
X r->num = tmp;
X return r;
X}
X
X
X/*
X * Return the lowest prime factor of a number.
X * Search is conducted for the specified number of primes.
X * Returns one if no factor was found.
X */
XNUMBER *
Xqlowfactor(q1, q2)
X NUMBER *q1, *q2;
X{
X if (qisfrac(q1) || qisfrac(q2))
X math_error("Non-integers for lowfactor");
X return itoq(zlowfactor(q1->num, ztoi(q2->num)));
X}
X
X
X/*
X * Return the number of places after the decimal point needed to exactly
X * represent the specified number as a real number. Integers return zero,
X * and non-terminating decimals return minus one. Examples:
X * qplaces(1/7)=-1, qplaces(3/10)= 1, qplaces(1/8)=3, qplaces(4)=0.
X */
Xlong
Xqplaces(q)
X NUMBER *q;
X{
X long twopow, fivepow;
X HALF fiveval[2];
X ZVALUE five;
X ZVALUE tmp;
X
X if (qisint(q)) /* no decimal places if number is integer */
X return 0;
X /*
X * The number of decimal places of a fraction in lowest terms is finite
X * if an only if the denominator is of the form 2^A * 5^B, and then the
X * number of decimal places is equal to MAX(A, B).
X */
X five.sign = 0;
X five.len = 1;
X five.v = fiveval;
X fiveval[0] = 5;
X fivepow = zfacrem(q->den, five, &tmp);
X if (!zisonebit(tmp)) {
X zfree(tmp);
X return -1;
X }
X twopow = zlowbit(tmp);
X zfree(tmp);
X if (twopow < fivepow)
X twopow = fivepow;
X return twopow;
X}
X
X
X/*
X * Perform a probabilistic primality test (algorithm P in Knuth).
X * Returns FALSE if definitely not prime, or TRUE if probably prime.
X * Second arg determines how many times to check for primality.
X */
XBOOL
Xqprimetest(q1, q2)
X NUMBER *q1, *q2;
X{
X if (qisfrac(q1) || qisfrac(q2) || qisneg(q2))
X math_error("Bad arguments for qprimetest");
X return zprimetest(q1->num, qtoi(q2));
X}
X
X
X/*
X * Return a trivial hash value for a number.
X */
XHASH
Xqhash(q)
X NUMBER *q;
X{
X HASH hash;
X
X hash = zhash(q->num);
X if (qisfrac(q))
X hash += zhash(q->den) * 2000003;
X return hash;
X}
X
X/* END CODE */
SHAR_EOF
chmod 0644 calc2.9.0/qfunc.c || echo "restore of calc2.9.0/qfunc.c fails"
set `wc -c calc2.9.0/qfunc.c`;Sum=$1
if test "$Sum" != "24730"
then echo original size 24730, current size $Sum;fi
echo "x - extracting calc2.9.0/qio.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/qio.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X *
X * Scanf and printf routines for arbitrary precision rational numbers
X */
X
X#include "stdarg.h"
X#include "qmath.h"
X
X
X#define PUTCHAR(ch) math_chr(ch)
X#define PUTSTR(str) math_str(str)
X#define PRINTF1(fmt, a1) math_fmt(fmt, a1)
X#define PRINTF2(fmt, a1, a2) math_fmt(fmt, a1, a2)
X
X
X#if 0
Xstatic long etoalen;
Xstatic char *etoabuf = NULL;
X#endif
X
Xstatic long scalefactor;
Xstatic ZVALUE scalenumber = { 0, 0, 0 };
X
X
X/*
X * Print a formatted string containing arbitrary numbers, similar to printf.
X * ALL numeric arguments to this routine are rational NUMBERs.
X * Various forms of printing such numbers are supplied, in addition
X * to strings and characters. Output can actually be to any FILE
X * stream or a string.
X */
X#ifdef VARARGS
X# define VA_ALIST1 fmt, va_alist
X# define VA_DCL1 char *fmt; va_dcl
X#else
X# ifdef __STDC__
X# define VA_ALIST1 char *fmt, ...
X# define VA_DCL1
X# else
X# define VA_ALIST1 fmt
X# define VA_DCL1 char *fmt;
X# endif
X#endif
X/*VARARGS*/
Xvoid
Xqprintf(VA_ALIST1)
X VA_DCL1
X{
X va_list ap;
X NUMBER *q;
X int ch, sign;
X long width, precision;
X
X#ifdef VARARGS
X va_start(ap);
X#else
X va_start(ap, fmt);
X#endif
X while ((ch = *fmt++) != '\0') {
X if (ch == '\\') {
X ch = *fmt++;
X switch (ch) {
X case 'n': ch = '\n'; break;
X case 'r': ch = '\r'; break;
X case 't': ch = '\t'; break;
X case 'f': ch = '\f'; break;
X case 'v': ch = '\v'; break;
X case 'b': ch = '\b'; break;
X case 0:
X va_end(ap);
X return;
X }
X PUTCHAR(ch);
X continue;
X }
X if (ch != '%') {
X PUTCHAR(ch);
X continue;
X }
X ch = *fmt++;
X width = 0; precision = 8; sign = 1;
Xpercent: ;
X switch (ch) {
X case 'd':
X q = va_arg(ap, NUMBER *);
X qprintfd(q, width);
X break;
X case 'f':
X q = va_arg(ap, NUMBER *);
X qprintff(q, width, precision);
X break;
X case 'e':
X q = va_arg(ap, NUMBER *);
X qprintfe(q, width, precision);
X break;
X case 'r':
X case 'R':
X q = va_arg(ap, NUMBER *);
X qprintfr(q, width, (BOOL) (ch == 'R'));
X break;
X case 'N':
X q = va_arg(ap, NUMBER *);
X zprintval(q->num, 0L, width);
X break;
X case 'D':
X q = va_arg(ap, NUMBER *);
X zprintval(q->den, 0L, width);
X break;
X case 'o':
X q = va_arg(ap, NUMBER *);
X qprintfo(q, width);
X break;
X case 'x':
X q = va_arg(ap, NUMBER *);
X qprintfx(q, width);
X break;
X case 'b':
X q = va_arg(ap, NUMBER *);
X qprintfb(q, width);
X break;
X case 's':
X PUTSTR(va_arg(ap, char *));
X break;
X case 'c':
X PUTCHAR(va_arg(ap, int));
X break;
X case 0:
X va_end(ap);
X return;
X case '-':
X sign = -1;
X ch = *fmt++;
X default:
X if (('0' <= ch && ch <= '9') || ch == '.' || ch == '*') {
X if (ch == '*') {
X q = va_arg(ap, NUMBER *);
X width = sign * qtoi(q);
X ch = *fmt++;
X } else if (ch != '.') {
X width = ch - '0';
X while ('0' <= (ch = *fmt++) && ch <= '9')
X width = width * 10 + ch - '0';
X width *= sign;
X }
X if (ch == '.') {
X if ((ch = *fmt++) == '*') {
X q = va_arg(ap, NUMBER *);
X precision = qtoi(q);
X ch = *fmt++;
X } else {
X precision = 0;
X while ('0' <= (ch = *fmt++) && ch <= '9')
X precision = precision * 10 + ch - '0';
X }
X }
X goto percent;
X }
X }
X }
X va_end(ap);
X}
X
X
X#if 0
X/*
X * Read a number from the specified FILE stream (NULL means stdin).
X * The number can be an integer, a fraction, a real number, an
X * exponential number, or a hex, octal or binary number. Leading blanks
X * are skipped. Illegal numbers return NULL. Unrecognized characters
X * remain to be read on the line.
X * q = qreadval(fp);
X */
XNUMBER *
Xqreadval(fp)
X FILE *fp; /* file stream to read from (or NULL) */
X{
X NUMBER *r; /* returned number */
X char *cp; /* current buffer location */
X long savecc; /* characters saved in buffer */
X long scancc; /* characters parsed correctly */
X int ch; /* current character */
X
X if (fp == NULL)
X fp = stdin;
X if (etoabuf == NULL) {
X etoabuf = (char *)malloc(OUTBUFSIZE + 2);
X if (etoabuf == NULL)
X return NULL;
X etoalen = OUTBUFSIZE;
X }
X cp = etoabuf;
X ch = fgetc(fp);
X while ((ch == ' ') || (ch == '\t'))
X ch = fgetc(fp);
X savecc = 0;
X for (;;) {
X if (ch == EOF)
X return NULL;
X if (savecc >= etoalen)
X {
X cp = (char *)realloc(etoabuf, etoalen + OUTBUFSIZE + 2);
X if (cp == NULL)
X return NULL;
X etoabuf = cp;
X etoalen += OUTBUFSIZE;
X cp += savecc;
X }
X *cp++ = (char)ch;
X *cp = '\0';
X scancc = qparse(etoabuf, QPF_SLASH);
X if (scancc != ++savecc)
X break;
X ch = fgetc(fp);
X }
X ungetc(ch, fp);
X if (scancc < 0)
X return NULL;
X r = atoq(etoabuf);
X if (ziszero(r->den)) {
X qfree(r);
X r = NULL;
X }
X return r;
X}
X#endif
X
X
X/*
X * Print a number in the specified output mode.
X * If MODE_DEFAULT is given, then the default output mode is used.
X * Any approximate output is flagged with a leading tilde.
X * Integers are always printed as themselves.
X */
Xvoid
Xqprintnum(q, outmode)
X NUMBER *q;
X{
X NUMBER tmpval;
X long prec, exp;
X
X if (outmode == MODE_DEFAULT)
X outmode = _outmode_;
X if ((outmode == MODE_FRAC) || ((outmode == MODE_REAL) && qisint(q))) {
X qprintfr(q, 0L, FALSE);
X return;
X }
X switch (outmode) {
X case MODE_INT:
X if (qisfrac(q))
X PUTCHAR('~');
X qprintfd(q, 0L);
X break;
X
X case MODE_REAL:
X prec = qplaces(q);
X if ((prec < 0) || (prec > _outdigits_)) {
X prec = _outdigits_;
X PUTCHAR('~');
X }
X qprintff(q, 0L, prec);
X break;
X
X case MODE_EXP:
X if (qiszero(q)) {
X PUTCHAR('0');
X return;
X }
X tmpval = *q;
X tmpval.num.sign = 0;
X exp = qilog10(&tmpval);
X if (exp == 0) { /* in range to output as real */
X qprintnum(q, MODE_REAL);
X return;
X }
X tmpval.num = _one_;
X tmpval.den = _one_;
X if (exp > 0)
X ztenpow(exp, &tmpval.den);
X else
X ztenpow(-exp, &tmpval.num);
X q = qmul(q, &tmpval);
X zfree(tmpval.num);
X zfree(tmpval.den);
X qprintnum(q, MODE_REAL);
X qfree(q);
X PRINTF1("e%ld", exp);
X break;
X
X case MODE_HEX:
X qprintfx(q, 0L);
X break;
X
X case MODE_OCTAL:
X qprintfo(q, 0L);
X break;
X
X case MODE_BINARY:
X qprintfb(q, 0L);
X break;
X
X default:
X math_error("Bad mode for print");
X }
X}
X
X
X/*
X * Print a number in floating point representation.
X * Example: 193.784
X */
Xvoid
Xqprintff(q, width, precision)
X NUMBER *q;
X long width;
X long precision;
X{
X ZVALUE z, z1;
X
X if (precision != scalefactor) {
X if (scalenumber.v)
X zfree(scalenumber);
X ztenpow(precision, &scalenumber);
X scalefactor = precision;
X }
X if (scalenumber.v)
X zmul(q->num, scalenumber, &z);
X else
X z = q->num;
X if (qisfrac(q)) {
X zquo(z, q->den, &z1);
X if (z.v != q->num.v)
X zfree(z);
X z = z1;
X }
X if (qisneg(q) && ziszero(z))
X PUTCHAR('-');
X zprintval(z, precision, width);
X if (z.v != q->num.v)
X zfree(z);
X}
X
X
X/*
X * Print a number in exponential notation.
X * Example: 4.1856e34
X */
X/*ARGSUSED*/
Xvoid
Xqprintfe(q, width, precision)
X register NUMBER *q;
X long width;
X long precision;
X{
X long exponent;
X NUMBER q2;
X ZVALUE num, den, tenpow, tmp;
X
X if (qiszero(q)) {
X PUTSTR("0.0");
X return;
X }
X num = q->num;
X den = q->den;
X num.sign = 0;
X exponent = zdigits(num) - zdigits(den);
X if (exponent > 0) {
X ztenpow(exponent, &tenpow);
X zmul(den, tenpow, &tmp);
X zfree(tenpow);
X den = tmp;
X }
X if (exponent < 0) {
X ztenpow(-exponent, &tenpow);
X zmul(num, tenpow, &tmp);
X zfree(tenpow);
X num = tmp;
X }
X if (zrel(num, den) < 0) {
X zmuli(num, 10L, &tmp);
X if (num.v != q->num.v)
X zfree(num);
X num = tmp;
X exponent--;
X }
X q2.num = num;
X q2.den = den;
X q2.num.sign = q->num.sign;
X qprintff(&q2, 0L, precision);
X if (exponent)
X PRINTF1("e%ld", exponent);
X if (num.v != q->num.v)
X zfree(num);
X if (den.v != q->den.v)
X zfree(den);
X}
X
X
X/*
X * Print a number in rational representation.
X * Example: 397/37
X */
Xvoid
Xqprintfr(q, width, force)
X NUMBER *q;
X long width;
X BOOL force;
X{
X zprintval(q->num, 0L, width);
X if (force || qisfrac(q)) {
X PUTCHAR('/');
X zprintval(q->den, 0L, width);
X }
X}
X
X
X/*
X * Print a number as an integer (truncating fractional part).
X * Example: 958421
X */
Xvoid
Xqprintfd(q, width)
X NUMBER *q;
X long width;
X{
X ZVALUE z;
X
X if (qisfrac(q)) {
X zquo(q->num, q->den, &z);
X zprintval(z, 0L, width);
X zfree(z);
X } else
X zprintval(q->num, 0L, width);
X}
X
X
X/*
X * Print a number in hex.
X * This prints the numerator and denominator in hex.
X */
Xvoid
Xqprintfx(q, width)
X NUMBER *q;
X long width;
X{
X zprintx(q->num, width);
X if (qisfrac(q)) {
X PUTCHAR('/');
X zprintx(q->den, 0L);
X }
X}
X
X
X/*
X * Print a number in binary.
X * This prints the numerator and denominator in binary.
X */
Xvoid
Xqprintfb(q, width)
X NUMBER *q;
X long width;
X{
X zprintb(q->num, width);
X if (qisfrac(q)) {
X PUTCHAR('/');
X zprintb(q->den, 0L);
X }
X}
X
X
X/*
X * Print a number in octal.
X * This prints the numerator and denominator in octal.
X */
Xvoid
Xqprintfo(q, width)
X NUMBER *q;
X long width;
X{
X zprinto(q->num, width);
X if (qisfrac(q)) {
X PUTCHAR('/');
X zprinto(q->den, 0L);
X }
X}
X
X
X/*
X * Convert a string to a number in rational, floating point,
X * exponential notation, hex, or octal.
X * q = atoq(string);
X */
XNUMBER *
Xatoq(s)
X register char *s;
X{
X register NUMBER *q;
X register char *t;
X ZVALUE div, newnum, newden, tmp;
X long decimals, exp;
X BOOL hex, negexp;
X
X q = qalloc();
X decimals = 0;
X exp = 0;
X negexp = FALSE;
X hex = FALSE;
X t = s;
X if ((*t == '+') || (*t == '-'))
X t++;
X if ((*t == '0') && ((t[1] == 'x') || (t[1] == 'X'))) {
X hex = TRUE;
X t += 2;
X }
X while (((*t >= '0') && (*t <= '9')) || (hex &&
X (((*t >= 'a') && (*t <= 'f')) || ((*t >= 'A') && (*t <= 'F')))))
X t++;
X if (*t == '/') {
X t++;
X atoz(t, &q->den);
X } else if ((*t == '.') || (*t == 'e') || (*t == 'E')) {
X if (*t == '.') {
X t++;
X while ((*t >= '0') && (*t <= '9')) {
X t++;
X decimals++;
X }
X }
X /*
X * Parse exponent if any
X */
X if ((*t == 'e') || (*t == 'E')) {
X t++;
X if (*t == '+')
X t++;
X else if (*t == '-') {
X negexp = TRUE;
X t++;
X }
X while ((*t >= '0') && (*t <= '9')) {
X exp = (exp * 10) + *t++ - '0';
X if (exp > 1000000)
X math_error("Exponent too large");
X }
X }
X ztenpow(decimals, &q->den);
X }
X atoz(s, &q->num);
X if (qiszero(q)) {
X qfree(q);
X return qlink(&_qzero_);
X }
X /*
X * Apply the exponential if any
X */
X if (exp) {
X ztenpow(exp, &tmp);
X if (negexp) {
X zmul(q->den, tmp, &newden);
X zfree(q->den);
X q->den = newden;
X } else {
X zmul(q->num, tmp, &newnum);
X zfree(q->num);
X q->num = newnum;
X }
X zfree(tmp);
X }
X /*
X * Reduce the fraction to lowest terms
X */
X if (zisunit(q->num) || zisunit(q->den))
X return q;
X zgcd(q->num, q->den, &div);
X if (zisunit(div))
X return q;
X zquo(q->num, div, &newnum);
X zfree(q->num);
X zquo(q->den, div, &newden);
X zfree(q->den);
X q->num = newnum;
X q->den = newden;
X return q;
X}
X
X
X/*
X * Parse a number in any of the various legal forms, and return the count
X * of characters that are part of a legal number. Numbers can be either a
X * decimal integer, possibly two decimal integers separated with a slash, a
X * floating point or exponential number, a hex number beginning with "0x",
X * a binary number beginning with "0b", or an octal number beginning with "0".
X * The flags argument modifies the end of number testing for ease in handling
X * fractions or complex numbers. Minus one is returned if the number format
X * is definitely illegal.
X */
Xlong
Xqparse(cp, flags)
X register char *cp;
X{
X char *oldcp;
X
X oldcp = cp;
X if ((*cp == '+') || (*cp == '-'))
X cp++;
X if ((*cp == '+') || (*cp == '-'))
X return -1;
X if ((*cp == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { /* hex */
X cp += 2;
X while (((*cp >= '0') && (*cp <= '9')) ||
X ((*cp >= 'a') && (*cp <= 'f')) ||
X ((*cp >= 'A') && (*cp <= 'F')))
X cp++;
X goto done;
X }
X if ((*cp == '0') && ((cp[1] == 'b') || (cp[1] == 'B'))) { /* binary */
X cp += 2;
X while ((*cp == '0') || (*cp == '1'))
X cp++;
X goto done;
X }
X if ((*cp == '0') && (cp[1] >= '0') && (cp[1] <= '9')) { /* octal */
X while ((*cp >= '0') && (*cp <= '7'))
X cp++;
X goto done;
X }
X /*
X * Number is decimal, but can still be a fraction or real or exponential.
X */
X while ((*cp >= '0') && (*cp <= '9'))
X cp++;
X if (*cp == '/' && flags & QPF_SLASH) { /* fraction */
X cp++;
X while ((*cp >= '0') && (*cp <= '9'))
X cp++;
X goto done;
X }
X if (*cp == '.') { /* floating point */
X cp++;
X while ((*cp >= '0') && (*cp <= '9'))
X cp++;
X }
X if ((*cp == 'e') || (*cp == 'E')) { /* exponential */
X cp++;
X if ((*cp == '+') || (*cp == '-'))
X cp++;
X if ((*cp == '+') || (*cp == '-'))
X return -1;
X while ((*cp >= '0') && (*cp <= '9'))
X cp++;
X }
X
Xdone:
X if (((*cp == 'i') || (*cp == 'I')) && (flags & QPF_IMAG))
X cp++;
X if ((*cp == '.') || ((*cp == '/') && (flags & QPF_SLASH)) ||
X ((*cp >= '0') && (*cp <= '9')) ||
X ((*cp >= 'a') && (*cp <= 'z')) ||
X ((*cp >= 'A') && (*cp <= 'Z')))
X return -1;
X return (cp - oldcp);
X}
X
X/* END CODE */
SHAR_EOF
chmod 0644 calc2.9.0/qio.c || echo "restore of calc2.9.0/qio.c fails"
set `wc -c calc2.9.0/qio.c`;Sum=$1
if test "$Sum" != "12895"
then echo original size 12895, current size $Sum;fi
echo "x - extracting calc2.9.0/qmath.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/qmath.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X *
X * Extended precision rational arithmetic primitive routines
X */
X
X#include "qmath.h"
X
X
XNUMBER _qzero_ = { { _zeroval_, 1, 0 }, { _oneval_, 1, 0 }, 1 };
XNUMBER _qone_ = { { _oneval_, 1, 0 }, { _oneval_, 1, 0 }, 1 };
Xstatic NUMBER _qtwo_ = { { _twoval_, 1, 0 }, { _oneval_, 1, 0 }, 1 };
Xstatic NUMBER _qten_ = { { _tenval_, 1, 0 }, { _oneval_, 1, 0 }, 1 };
XNUMBER _qnegone_ = { { _oneval_, 1, 1 }, { _oneval_, 1, 0 }, 1 };
XNUMBER _qonehalf_ = { { _oneval_, 1, 0 }, { _twoval_, 1, 0 }, 1 };
X
X
X/*
X * Create another copy of a number.
X * q2 = qcopy(q1);
X */
XNUMBER *
Xqcopy(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X r = qalloc();
X r->num.sign = q->num.sign;
X if (!zisunit(q->num)) {
X r->num.len = q->num.len;
X r->num.v = alloc(r->num.len);
X zcopyval(q->num, r->num);
X }
X if (!zisunit(q->den)) {
X r->den.len = q->den.len;
X r->den.v = alloc(r->den.len);
X zcopyval(q->den, r->den);
X }
X return r;
X}
X
X
X/*
X * Convert a number to a normal integer.
X * i = qtoi(q);
X */
Xlong
Xqtoi(q)
X register NUMBER *q;
X{
X long i;
X ZVALUE res;
X
X if (qisint(q))
X return ztoi(q->num);
X zquo(q->num, q->den, &res);
X i = ztoi(res);
X zfree(res);
X return i;
X}
X
X
X/*
X * Convert a normal integer into a number.
X * q = itoq(i);
X */
XNUMBER *
Xitoq(i)
X long i;
X{
X register NUMBER *q;
X
X if ((i >= -1) && (i <= 10)) {
X switch ((int) i) {
X case 0: q = &_qzero_; break;
X case 1: q = &_qone_; break;
X case 2: q = &_qtwo_; break;
X case 10: q = &_qten_; break;
X case -1: q = &_qnegone_; break;
X default: q = NULL;
X }
X if (q)
X return qlink(q);
X }
X q = qalloc();
X itoz(i, &q->num);
X return q;
X}
X
X
X/*
X * Create a number from the given integral numerator and denominator.
X * q = iitoq(inum, iden);
X */
XNUMBER *
Xiitoq(inum, iden)
X long inum, iden;
X{
X register NUMBER *q;
X long d;
X BOOL sign;
X
X if (iden == 0)
X math_error("Division by zero");
X if (inum == 0)
X return qlink(&_qzero_);
X sign = 0;
X if (inum < 0) {
X sign = 1;
X inum = -inum;
X }
X if (iden < 0) {
X sign = 1 - sign;
X iden = -iden;
X }
X d = iigcd(inum, iden);
X inum /= d;
X iden /= d;
X if (iden == 1)
X return itoq(sign ? -inum : inum);
X q = qalloc();
X if (inum != 1)
X itoz(inum, &q->num);
X itoz(iden, &q->den);
X q->num.sign = sign;
X return q;
X}
X
X
X/*
X * Add two numbers to each other.
X * q3 = qadd(q1, q2);
X */
XNUMBER *
Xqadd(q1, q2)
X register NUMBER *q1, *q2;
X{
X NUMBER *r;
X ZVALUE t1, t2, temp, d1, d2, vpd1, upd1;
X
X if (qiszero(q1))
X return qlink(q2);
X if (qiszero(q2))
X return qlink(q1);
X r = qalloc();
X /*
X * If either number is an integer, then the result is easy.
X */
X if (qisint(q1) && qisint(q2)) {
X zadd(q1->num, q2->num, &r->num);
X return r;
X }
X if (qisint(q2)) {
X zmul(q1->den, q2->num, &temp);
X zadd(q1->num, temp, &r->num);
X zfree(temp);
X zcopy(q1->den, &r->den);
X return r;
X }
X if (qisint(q1)) {
X zmul(q2->den, q1->num, &temp);
X zadd(q2->num, temp, &r->num);
X zfree(temp);
X zcopy(q2->den, &r->den);
X return r;
X }
X /*
X * Both arguments are true fractions, so we need more work.
X * If the denominators are relatively prime, then the answer is the
X * straightforward cross product result with no need for reduction.
X */
X zgcd(q1->den, q2->den, &d1);
X if (zisunit(d1)) {
X zfree(d1);
X zmul(q1->num, q2->den, &t1);
X zmul(q1->den, q2->num, &t2);
X zadd(t1, t2, &r->num);
X zfree(t1);
X zfree(t2);
X zmul(q1->den, q2->den, &r->den);
X return r;
X }
X /*
X * The calculation is now more complicated.
X * See Knuth Vol 2 for details.
X */
X zquo(q2->den, d1, &vpd1);
X zquo(q1->den, d1, &upd1);
X zmul(q1->num, vpd1, &t1);
X zmul(q2->num, upd1, &t2);
X zadd(t1, t2, &temp);
X zfree(t1);
X zfree(t2);
X zfree(vpd1);
X zgcd(temp, d1, &d2);
X zfree(d1);
X if (zisunit(d2)) {
X zfree(d2);
X r->num = temp;
X zmul(upd1, q2->den, &r->den);
X zfree(upd1);
X return r;
X }
X zquo(temp, d2, &r->num);
X zfree(temp);
X zquo(q2->den, d2, &temp);
X zfree(d2);
X zmul(temp, upd1, &r->den);
X zfree(temp);
X zfree(upd1);
X return r;
X}
X
X
X/*
X * Subtract one number from another.
X * q3 = qsub(q1, q2);
X */
XNUMBER *
Xqsub(q1, q2)
X register NUMBER *q1, *q2;
X{
X NUMBER t, *r;
X
X if (q1 == q2)
X return qlink(&_qzero_);
X if (qiszero(q2))
X return qlink(q1);
X if (qisint(q1) && qisint(q2)) {
X r = qalloc();
X zsub(q1->num, q2->num, &r->num);
X return r;
X }
X t = *q2;
X t.num.sign = !t.num.sign;
X return qadd(q1, &t);
X}
X
X
X/*
X * Increment a number by one.
X */
XNUMBER *
Xqinc(q)
X NUMBER *q;
X{
X NUMBER *r;
X
X r = qalloc();
X if (qisint(q)) {
X zadd(q->num, _one_, &r->num);
X return r;
X }
X zadd(q->num, q->den, &r->num);
X zcopy(q->den, &r->den);
X return r;
X}
X
X
X/*
X * Decrement a number by one.
X */
XNUMBER *
Xqdec(q)
X NUMBER *q;
X{
X NUMBER *r;
X
X r = qalloc();
X if (qisint(q)) {
X zsub(q->num, _one_, &r->num);
X return r;
X }
X zsub(q->num, q->den, &r->num);
X zcopy(q->den, &r->den);
X return r;
X}
X
X
X/*
X * Add a normal small integer value to an arbitrary number.
X */
XNUMBER *
Xqaddi(q1, n)
X NUMBER *q1;
X long n;
X{
X NUMBER addnum; /* temporary number */
X HALF addval[2]; /* value of small number */
X BOOL neg; /* TRUE if number is neg */
X
X if (n == 0)
X return qlink(q1);
X if (n == 1)
X return qinc(q1);
X if (n == -1)
X return qdec(q1);
X if (qiszero(q1))
X return itoq(n);
X addnum.num.sign = 0;
X addnum.num.len = 1;
X addnum.num.v = addval;
X addnum.den = _one_;
X neg = (n < 0);
X if (neg)
X n = -n;
X addval[0] = (HALF) n;
X n = (((FULL) n) >> BASEB);
X if (n) {
X addval[1] = (HALF) n;
X addnum.num.len = 2;
X }
X if (neg)
X return qsub(q1, &addnum);
X else
X return qadd(q1, &addnum);
X}
X
X
X/*
X * Multiply two numbers.
X * q3 = qmul(q1, q2);
X */
XNUMBER *
Xqmul(q1, q2)
X register NUMBER *q1, *q2;
X{
X NUMBER *r; /* returned value */
X ZVALUE n1, n2, d1, d2; /* numerators and denominators */
X ZVALUE tmp;
X
X if (qiszero(q1) || qiszero(q2))
X return qlink(&_qzero_);
X if (qisone(q1))
X return qlink(q2);
X if (qisone(q2))
X return qlink(q1);
X if (qisint(q1) && qisint(q2)) { /* easy results if integers */
X r = qalloc();
X zmul(q1->num, q2->num, &r->num);
X return r;
X }
X n1 = q1->num;
X n2 = q2->num;
X d1 = q1->den;
X d2 = q2->den;
X if (ziszero(d1) || ziszero(d2))
X math_error("Division by zero");
X if (ziszero(n1) || ziszero(n2))
X return qlink(&_qzero_);
X if (!zisunit(n1) && !zisunit(d2)) { /* possibly reduce */
X zgcd(n1, d2, &tmp);
X if (!zisunit(tmp)) {
X zquo(q1->num, tmp, &n1);
X zquo(q2->den, tmp, &d2);
X }
X zfree(tmp);
X }
X if (!zisunit(n2) && !zisunit(d1)) { /* again possibly reduce */
X zgcd(n2, d1, &tmp);
X if (!zisunit(tmp)) {
X zquo(q2->num, tmp, &n2);
X zquo(q1->den, tmp, &d1);
X }
X zfree(tmp);
X }
X r = qalloc();
X zmul(n1, n2, &r->num);
X zmul(d1, d2, &r->den);
X if (q1->num.v != n1.v)
X zfree(n1);
X if (q1->den.v != d1.v)
X zfree(d1);
X if (q2->num.v != n2.v)
X zfree(n2);
X if (q2->den.v != d2.v)
X zfree(d2);
X return r;
X}
X
X
X/*
X * Multiply a number by a small integer.
X * q2 = qmuli(q1, n);
X */
XNUMBER *
Xqmuli(q, n)
X NUMBER *q;
X long n;
X{
X NUMBER *r;
X long d; /* gcd of multiplier and denominator */
X int sign;
X
X if ((n == 0) || qiszero(q))
X return qlink(&_qzero_);
X if (n == 1)
X return qlink(q);
X r = qalloc();
X if (qisint(q)) {
X zmuli(q->num, n, &r->num);
X return r;
X }
X sign = 1;
X if (n < 0) {
X n = -n;
X sign = -1;
X }
X d = zmodi(q->den, n);
X d = iigcd(d, n);
X zmuli(q->num, (n * sign) / d, &r->num);
X (void) zdivi(q->den, d, &r->den);
X return r;
X}
X
X
X/*
X * Divide two numbers (as fractions).
X * q3 = qdiv(q1, q2);
X */
XNUMBER *
Xqdiv(q1, q2)
X register NUMBER *q1, *q2;
X{
X NUMBER temp;
X
X if (qiszero(q2))
X math_error("Division by zero");
X if ((q1 == q2) || !qcmp(q1, q2))
X return qlink(&_qone_);
X if (qisone(q1))
X return qinv(q2);
X temp.num = q2->den;
X temp.den = q2->num;
X temp.num.sign = temp.den.sign;
X temp.den.sign = 0;
X temp.links = 1;
X return qmul(q1, &temp);
X}
X
X
X/*
X * Divide a number by a small integer.
X * q2 = qdivi(q1, n);
X */
XNUMBER *
Xqdivi(q, n)
X NUMBER *q;
X long n;
X{
X NUMBER *r;
X long d; /* gcd of divisor and numerator */
X int sign;
X
X if (n == 0)
X math_error("Division by zero");
X if ((n == 1) || qiszero(q))
X return qlink(q);
X sign = 1;
X if (n < 0) {
X n = -n;
X sign = -1;
X }
X r = qalloc();
X d = zmodi(q->num, n);
X d = iigcd(d, n);
X (void) zdivi(q->num, d * sign, &r->num);
X zmuli(q->den, n / d, &r->den);
X return r;
X}
X
X
X/*
X * Return the quotient when one number is divided by another.
X * This works for fractional values also, and in all cases:
X * qquo(q1, q2) = int(q1 / q2).
X */
XNUMBER *
Xqquo(q1, q2)
X register NUMBER *q1, *q2;
X{
X ZVALUE num, den, res;
X NUMBER *q;
X
X if (zisunit(q1->num))
X num = q2->den;
X else if (zisunit(q2->den))
X num = q1->num;
X else
X zmul(q1->num, q2->den, &num);
X if (zisunit(q1->den))
X den = q2->num;
X else if (zisunit(q2->num))
X den = q1->den;
X else
X zmul(q1->den, q2->num, &den);
X zquo(num, den, &res);
X if ((num.v != q2->den.v) && (num.v != q1->num.v))
X zfree(num);
X if ((den.v != q2->num.v) && (den.v != q1->den.v))
X zfree(den);
X if (ziszero(res)) {
X zfree(res);
X return qlink(&_qzero_);
X }
X res.sign = (q1->num.sign != q2->num.sign);
X if (zisunit(res)) {
X q = (res.sign ? &_qnegone_ : &_qone_);
X zfree(res);
X return qlink(q);
X }
X q = qalloc();
X q->num = res;
X return q;
X}
X
X
X/*
X * Return the absolute value of a number.
X * q2 = qabs(q1);
X */
XNUMBER *
Xqabs(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (q->num.sign == 0)
X return qlink(q);
X r = qalloc();
X if (!zisunit(q->num))
X zcopy(q->num, &r->num);
X if (!zisunit(q->den))
X zcopy(q->den, &r->den);
X r->num.sign = 0;
X return r;
X}
X
X
X/*
X * Negate a number.
X * q2 = qneg(q1);
X */
XNUMBER *
Xqneg(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (qiszero(q))
X return qlink(&_qzero_);
X r = qalloc();
X if (!zisunit(q->num))
X zcopy(q->num, &r->num);
X if (!zisunit(q->den))
X zcopy(q->den, &r->den);
X r->num.sign = !q->num.sign;
X return r;
X}
X
X
X/*
X * Return the sign of a number (-1, 0 or 1)
X */
XNUMBER *
Xqsign(q)
X NUMBER *q;
X{
X if (qiszero(q))
X return qlink(&_qzero_);
X if (qisneg(q))
X return qlink(&_qnegone_);
X return qlink(&_qone_);
X}
X
X
X/*
X * Invert a number.
X * q2 = qinv(q1);
X */
XNUMBER *
Xqinv(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (qisunit(q)) {
X r = (qisneg(q) ? &_qnegone_ : &_qone_);
X return qlink(r);
X }
X if (qiszero(q))
X math_error("Division by zero");
X r = qalloc();
X if (!zisunit(q->num))
X zcopy(q->num, &r->den);
X if (!zisunit(q->den))
X zcopy(q->den, &r->num);
X r->num.sign = q->num.sign;
X r->den.sign = 0;
X return r;
X}
X
X
X/*
X * Return just the numerator of a number.
X * q2 = qnum(q1);
X */
XNUMBER *
Xqnum(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (qisint(q))
X return qlink(q);
X if (zisunit(q->num)) {
X r = (qisneg(q) ? &_qnegone_ : &_qone_);
X return qlink(r);
X }
X r = qalloc();
X zcopy(q->num, &r->num);
X return r;
X}
X
X
X/*
X * Return just the denominator of a number.
X * q2 = qden(q1);
X */
XNUMBER *
Xqden(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (qisint(q))
X return qlink(&_qone_);
X r = qalloc();
X zcopy(q->den, &r->num);
X return r;
X}
X
X
X/*
X * Return the fractional part of a number.
X * q2 = qfrac(q1);
X */
XNUMBER *
Xqfrac(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (qisint(q))
X return qlink(&_qzero_);
X if ((q->num.len < q->den.len) || ((q->num.len == q->den.len) &&
X (q->num.v[q->num.len - 1] < q->den.v[q->num.len - 1])))
X return qlink(q);
X r = qalloc();
X zmod(q->num, q->den, &r->num);
X zcopy(q->den, &r->den);
X r->num.sign = q->num.sign;
X return r;
X}
X
X
X/*
X * Return the integral part of a number.
X * q2 = qint(q1);
X */
XNUMBER *
Xqint(q)
X register NUMBER *q;
X{
X register NUMBER *r;
X
X if (qisint(q))
X return qlink(q);
X if ((q->num.len < q->den.len) || ((q->num.len == q->den.len) &&
X (q->num.v[q->num.len - 1] < q->den.v[q->num.len - 1])))
SHAR_EOF
echo "End of part 8"
echo "File calc2.9.0/qmath.c is continued in part 9"
echo "9" > s2_seq_.tmp
exit 0