home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-07 | 59.5 KB | 2,474 lines |
- Newsgroups: comp.sources.unix
- From: dbell@canb.auug.org.au (David I. Bell)
- Subject: v27i136: calc-2.9.0 - arbitrary precision C-like programmable calculator, Part09/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 136
- Archive-Name: calc-2.9.0/part09
-
- #!/bin/sh
- # this is part 9 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file calc2.9.0/qmath.c continued
- #
- CurArch=9
- 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/qmath.c"
- sed 's/^X//' << 'SHAR_EOF' >> calc2.9.0/qmath.c
- X return qlink(&_qzero_);
- X r = qalloc();
- X zquo(q->num, q->den, &r->num);
- X return r;
- X}
- X
- X
- X/*
- X * Compute the square of a number.
- X */
- XNUMBER *
- Xqsquare(q)
- X register NUMBER *q;
- X{
- X ZVALUE num, den;
- X
- X if (qiszero(q))
- X return qlink(&_qzero_);
- X if (qisunit(q))
- X return qlink(&_qone_);
- X num = q->num;
- X den = q->den;
- X q = qalloc();
- X if (!zisunit(num))
- X zsquare(num, &q->num);
- X if (!zisunit(den))
- X zsquare(den, &q->den);
- X return q;
- X}
- X
- X
- X/*
- X * Shift an integer by a given number of bits. This multiplies the number
- X * by the appropriate power of two. Positive numbers shift left, negative
- X * ones shift right. Low bits are truncated when shifting right.
- X */
- XNUMBER *
- Xqshift(q, n)
- X NUMBER *q;
- X long n;
- X{
- X register NUMBER *r;
- X
- X if (qisfrac(q))
- X math_error("Shift of non-integer");
- X if (qiszero(q) || (n == 0))
- X return qlink(q);
- X if (n <= -(q->num.len * BASEB))
- X return qlink(&_qzero_);
- X r = qalloc();
- X zshift(q->num, n, &r->num);
- X return r;
- X}
- X
- X
- X/*
- X * Scale a number by a power of two, as in:
- X * ans = q * 2^n.
- X * This is similar to shifting, except that fractions work.
- X */
- XNUMBER *
- Xqscale(q, pow)
- X NUMBER *q;
- X long pow;
- X{
- X long numshift, denshift, tmp;
- X NUMBER *r;
- X
- X if (qiszero(q) || (pow == 0))
- X return qlink(q);
- X if ((pow > 1000000L) || (pow < -1000000L))
- X math_error("Very large scale value");
- X numshift = zisodd(q->num) ? 0 : zlowbit(q->num);
- X denshift = zisodd(q->den) ? 0 : zlowbit(q->den);
- X if (pow > 0) {
- X tmp = pow;
- X if (tmp > denshift)
- X tmp = denshift;
- X denshift = -tmp;
- X numshift = (pow - tmp);
- X } else {
- X pow = -pow;
- X tmp = pow;
- X if (tmp > numshift)
- X tmp = numshift;
- X numshift = -tmp;
- X denshift = (pow - tmp);
- X }
- X r = qalloc();
- X if (numshift)
- X zshift(q->num, numshift, &r->num);
- X else
- X zcopy(q->num, &r->num);
- X if (denshift)
- X zshift(q->den, denshift, &r->den);
- X else
- X zcopy(q->den, &r->den);
- X return r;
- X}
- X
- X
- X/*
- X * Return the minimum of two numbers.
- X */
- XNUMBER *
- Xqmin(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X if (q1 == q2)
- X return qlink(q1);
- X if (qrel(q1, q2) > 0)
- X q1 = q2;
- X return qlink(q1);
- X}
- X
- X
- X/*
- X * Return the maximum of two numbers.
- X */
- XNUMBER *
- Xqmax(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X if (q1 == q2)
- X return qlink(q1);
- X if (qrel(q1, q2) < 0)
- X q1 = q2;
- X return qlink(q1);
- X}
- X
- X
- X/*
- X * Perform the logical OR of two integers.
- X */
- XNUMBER *
- Xqor(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X register NUMBER *r;
- X
- X if (qisfrac(q1) || qisfrac(q2))
- X math_error("Non-integers for logical or");
- X if ((q1 == q2) || qiszero(q2))
- X return qlink(q1);
- X if (qiszero(q1))
- X return qlink(q2);
- X r = qalloc();
- X zor(q1->num, q2->num, &r->num);
- X return r;
- X}
- X
- X
- X/*
- X * Perform the logical AND of two integers.
- X */
- XNUMBER *
- Xqand(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X register NUMBER *r;
- X ZVALUE res;
- X
- X if (qisfrac(q1) || qisfrac(q2))
- X math_error("Non-integers for logical and");
- X if (q1 == q2)
- X return qlink(q1);
- X if (qiszero(q1) || qiszero(q2))
- X return qlink(&_qzero_);
- X zand(q1->num, q2->num, &res);
- X if (ziszero(res)) {
- X zfree(res);
- X return qlink(&_qzero_);
- X }
- X r = qalloc();
- X r->num = res;
- X return r;
- X}
- X
- X
- X/*
- X * Perform the logical XOR of two integers.
- X */
- XNUMBER *
- Xqxor(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X register NUMBER *r;
- X ZVALUE res;
- X
- X if (qisfrac(q1) || qisfrac(q2))
- X math_error("Non-integers for logical xor");
- X if (q1 == q2)
- X return qlink(&_qzero_);
- X if (qiszero(q1))
- X return qlink(q2);
- X if (qiszero(q2))
- X return qlink(q1);
- X zxor(q1->num, q2->num, &res);
- X if (ziszero(res)) {
- X zfree(res);
- X return qlink(&_qzero_);
- X }
- X r = qalloc();
- X r->num = res;
- X return r;
- X}
- X
- X
- X#if 0
- X/*
- X * Return the number whose binary representation only has the specified
- X * bit set (counting from zero). This thus produces a given power of two.
- X */
- XNUMBER *
- Xqbitvalue(n)
- X long n;
- X{
- X register NUMBER *r;
- X
- X if (n <= 0)
- X return qlink(&_qone_);
- X r = qalloc();
- X zbitvalue(n, &r->num);
- X return r;
- X}
- X
- X
- X/*
- X * Test to see if the specified bit of a number is on (counted from zero).
- X * Returns TRUE if the bit is set, or FALSE if it is not.
- X * i = qbittest(q, n);
- X */
- XBOOL
- Xqbittest(q, n)
- X register NUMBER *q;
- X long n;
- X{
- X int x, y;
- X
- X if ((n < 0) || (n >= (q->num.len * BASEB)))
- X return FALSE;
- X x = q->num.v[n / BASEB];
- X y = (1 << (n % BASEB));
- X return ((x & y) != 0);
- X}
- X#endif
- X
- X
- X/*
- X * Return the precision of a number (usually for examining an epsilon value).
- X * This is the largest power of two whose reciprocal is not smaller in absolute
- X * value than the specified number. For example, qbitprec(1/100) = 6.
- X * Numbers larger than one have a precision of zero.
- X */
- Xlong
- Xqprecision(q)
- X NUMBER *q;
- X{
- X long r;
- X
- X if (qisint(q))
- X return 0;
- X if (zisunit(q->num))
- X return zhighbit(q->den);
- X r = zhighbit(q->den) - zhighbit(q->num) - 1;
- X if (r < 0)
- X r = 0;
- X return r;
- X}
- X
- X
- X#if 0
- X/*
- X * Return an integer indicating the sign of a number (-1, 0, or 1).
- X * i = qtst(q);
- X */
- XFLAG
- Xqtest(q)
- X register NUMBER *q;
- X{
- X if (!ztest(q->num))
- X return 0;
- X if (q->num.sign)
- X return -1;
- X return 1;
- X}
- X#endif
- X
- X
- X/*
- X * Determine whether or not one number exactly divides another one.
- X * Returns TRUE if the first number is an integer multiple of the second one.
- X */
- XBOOL
- Xqdivides(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X if (qiszero(q1))
- X return TRUE;
- X if (qisint(q1) && qisint(q2)) {
- X if (qisunit(q2))
- X return TRUE;
- X return zdivides(q1->num, q2->num);
- X }
- X return zdivides(q1->num, q2->num) && zdivides(q2->den, q1->den);
- X}
- X
- X
- X/*
- X * Compare two numbers and return an integer indicating their relative size.
- X * i = qrel(q1, q2);
- X */
- XFLAG
- Xqrel(q1, q2)
- X register NUMBER *q1, *q2;
- X{
- X ZVALUE z1, z2;
- X long wc1, wc2;
- X int sign;
- X int z1f = 0, z2f = 0;
- X
- X if (q1 == q2)
- X return 0;
- X sign = q2->num.sign - q1->num.sign;
- X if (sign)
- X return sign;
- X if (qiszero(q2))
- X return !qiszero(q1);
- X if (qiszero(q1))
- X return -1;
- X /*
- X * Make a quick comparison by calculating the number of words resulting as
- X * if we multiplied through by the denominators, and then comparing the
- X * word counts.
- X */
- X sign = 1;
- X if (qisneg(q1))
- X sign = -1;
- X wc1 = q1->num.len + q2->den.len;
- X wc2 = q2->num.len + q1->den.len;
- X if (wc1 < wc2 - 1)
- X return -sign;
- X if (wc2 < wc1 - 1)
- X return sign;
- X /*
- X * Quick check failed, must actually do the full comparison.
- X */
- X if (zisunit(q2->den))
- X z1 = q1->num;
- X else if (zisone(q1->num))
- X z1 = q2->den;
- X else {
- X z1f = 1;
- X zmul(q1->num, q2->den, &z1);
- X }
- X if (zisunit(q1->den))
- X z2 = q2->num;
- X else if (zisone(q2->num))
- X z2 = q1->den;
- X else {
- X z2f = 1;
- X zmul(q2->num, q1->den, &z2);
- X }
- X sign = zrel(z1, z2);
- X if (z1f)
- X zfree(z1);
- X if (z2f)
- X zfree(z2);
- X return sign;
- X}
- X
- X
- X/*
- X * Compare two numbers to see if they are equal.
- X * This differs from qrel in that the numbers are not ordered.
- X * Returns TRUE if they differ.
- X */
- XBOOL
- Xqcmp(q1, q2)
- X register NUMBER *q1, *q2;
- X{
- X if (q1 == q2)
- X return FALSE;
- X if ((q1->num.sign != q2->num.sign) || (q1->num.len != q2->num.len) ||
- X (q2->den.len != q2->den.len) || (*q1->num.v != *q2->num.v) ||
- X (*q1->den.v != *q2->den.v))
- X return TRUE;
- X if (zcmp(q1->num, q2->num))
- X return TRUE;
- X if (qisint(q1))
- X return FALSE;
- X return zcmp(q1->den, q2->den);
- X}
- X
- X
- X/*
- X * Compare a number against a normal small integer.
- X * Returns 1, 0, or -1, according to whether the first number is greater,
- X * equal, or less than the second number.
- X * n = qreli(q, n);
- X */
- XFLAG
- Xqreli(q, n)
- X NUMBER *q;
- X long n;
- X{
- X int sign;
- X ZVALUE num;
- X HALF h2[2];
- X NUMBER q2;
- X
- X sign = ztest(q->num); /* do trivial sign checks */
- X if (sign == 0) {
- X if (n > 0)
- X return -1;
- X return (n < 0);
- X }
- X if ((sign < 0) && (n >= 0))
- X return -1;
- X if ((sign > 0) && (n <= 0))
- X return 1;
- X n *= sign;
- X if (n == 1) { /* quick check against 1 or -1 */
- X num = q->num;
- X num.sign = 0;
- X return (sign * zrel(num, q->den));
- X }
- X num.sign = (sign < 0);
- X num.len = 1 + (n >= BASE);
- X num.v = h2;
- X h2[0] = (n & BASE1);
- X h2[1] = (n >> BASEB);
- X if (zisunit(q->den)) /* integer compare if no denominator */
- X return zrel(q->num, num);
- X q2.num = num;
- X q2.den = _one_;
- X q2.links = 1;
- X return qrel(q, &q2); /* full fractional compare */
- X}
- X
- X
- X/*
- X * Compare a number against a small integer to see if they are equal.
- X * Returns TRUE if they differ.
- X */
- XBOOL
- Xqcmpi(q, n)
- X NUMBER *q;
- X long n;
- X{
- X long len;
- X
- X len = q->num.len;
- X if ((len > 2) || qisfrac(q) || (q->num.sign != (n < 0)))
- X return TRUE;
- X if (n < 0)
- X n = -n;
- X if (((HALF)(n)) != q->num.v[0])
- X return TRUE;
- X n = ((FULL) n) >> BASEB;
- X return (((n != 0) != (len == 2)) || (n != q->num.v[1]));
- X}
- X
- X
- X/*
- X * Number node allocation routines
- X */
- X
- X#define NNALLOC 1000
- X
- Xunion allocNode {
- X NUMBER num;
- X union allocNode *link;
- X};
- X
- Xstatic union allocNode *freeNum;
- X
- X
- XNUMBER *
- Xqalloc()
- X{
- X register union allocNode *temp;
- X
- X if (!freeNum) {
- X freeNum = (union allocNode *)
- X malloc(sizeof (NUMBER) * NNALLOC);
- X if (freeNum == NULL)
- X math_error("Not enough memory");
- X temp = freeNum;
- X while (temp != freeNum + NNALLOC - 2) {
- X temp->link = temp+1;
- X ++temp;
- X }
- X }
- X temp = freeNum;
- X freeNum = temp->link;
- X temp->num.links = 1;
- X temp->num.num = _one_;
- X temp->num.den = _one_;
- X return &temp->num;
- X}
- X
- X
- Xvoid
- Xqfreenum(q)
- X register NUMBER *q;
- X{
- X union allocNode *a;
- X
- X if (q == NULL)
- X return;
- X zfree(q->num);
- X zfree(q->den);
- X a = (union allocNode *) q;
- X a->link = freeNum;
- X freeNum = a;
- X}
- X
- X/* END CODE */
- SHAR_EOF
- echo "File calc2.9.0/qmath.c is complete"
- chmod 0644 calc2.9.0/qmath.c || echo "restore of calc2.9.0/qmath.c fails"
- set `wc -c calc2.9.0/qmath.c`;Sum=$1
- if test "$Sum" != "20680"
- then echo original size 20680, current size $Sum;fi
- echo "x - extracting calc2.9.0/qmath.h (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/qmath.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 * Data structure declarations for extended precision rational arithmetic.
- X */
- X
- X#ifndef QMATH_H
- X#define QMATH_H
- X
- X#include "zmath.h"
- X
- X
- X/*
- X * Rational arithmetic definitions.
- X */
- Xtypedef struct {
- X ZVALUE num; /* numerator (containing sign) */
- X ZVALUE den; /* denominator (always positive) */
- X long links; /* number of links to this value */
- X} NUMBER;
- X
- X
- X/*
- X * Input. output, allocation, and conversion routines.
- X */
- Xextern NUMBER *qalloc MATH_PROTO((void));
- Xextern NUMBER *qcopy MATH_PROTO((NUMBER *q));
- Xextern NUMBER *iitoq MATH_PROTO((long i1, long i2));
- Xextern NUMBER *atoq MATH_PROTO((char *str));
- Xextern NUMBER *itoq MATH_PROTO((long i));
- Xextern long qtoi MATH_PROTO((NUMBER *q));
- Xextern long qparse MATH_PROTO((char *str, int flags));
- Xextern void qfreenum MATH_PROTO((NUMBER *q));
- Xextern void qprintnum MATH_PROTO((NUMBER *q, int mode));
- Xextern void qprintff MATH_PROTO((NUMBER *q, long width, long precision));
- Xextern void qprintfe MATH_PROTO((NUMBER *q, long width, long precision));
- Xextern void qprintfr MATH_PROTO((NUMBER *q, long width, BOOL force));
- Xextern void qprintfd MATH_PROTO((NUMBER *q, long width));
- Xextern void qprintfx MATH_PROTO((NUMBER *q, long width));
- Xextern void qprintfb MATH_PROTO((NUMBER *q, long width));
- Xextern void qprintfo MATH_PROTO((NUMBER *q, long width));
- X
- X
- X
- X/*
- X * Basic numeric routines.
- X */
- Xextern NUMBER *qaddi MATH_PROTO((NUMBER *q, long i));
- Xextern NUMBER *qmuli MATH_PROTO((NUMBER *q, long i));
- Xextern NUMBER *qdivi MATH_PROTO((NUMBER *q, long i));
- Xextern NUMBER *qadd MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qsub MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qmul MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qdiv MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qquo MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qmod MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qmin MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qmax MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qand MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qor MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qxor MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qpowermod MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *q3));
- Xextern NUMBER *qpowi MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qsquare MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qneg MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qsign MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qint MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qfrac MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qnum MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qden MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qinv MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qabs MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qinc MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qdec MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qshift MATH_PROTO((NUMBER *q, long n));
- Xextern NUMBER *qtrunc MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qround MATH_PROTO((NUMBER *q, long places));
- Xextern NUMBER *qbtrunc MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qbround MATH_PROTO((NUMBER *q, long places));
- Xextern NUMBER *qscale MATH_PROTO((NUMBER *q, long i));
- Xextern BOOL qdivides MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern BOOL qcmp MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern BOOL qcmpi MATH_PROTO((NUMBER *q, long i));
- Xextern FLAG qrel MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern FLAG qreli MATH_PROTO((NUMBER *q, long i));
- Xextern BOOL qisset MATH_PROTO((NUMBER *q, long i));
- X
- X
- X/*
- X * More complicated numeric functions.
- X */
- Xextern NUMBER *qcomb MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qgcd MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qlcm MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qfact MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qpfact MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qminv MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qfacrem MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qperm MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qgcdrem MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qlowfactor MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qfib MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qcfappr MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qisqrt MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qjacobi MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qiroot MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qbappr MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qlcmfact MATH_PROTO((NUMBER *q));
- Xextern NUMBER *qminmod MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qredcin MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qredcout MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qredcmul MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *q3));
- Xextern NUMBER *qredcsquare MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qredcpower MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *q3));
- Xextern BOOL qprimetest MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern BOOL qissquare MATH_PROTO((NUMBER *q));
- Xextern long qilog2 MATH_PROTO((NUMBER *q));
- Xextern long qilog10 MATH_PROTO((NUMBER *q));
- Xextern BOOL qcmpmod MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *q3));
- Xextern BOOL qquomod MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER **retdiv,
- X NUMBER **retmod));
- Xextern FLAG qnear MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *epsilon));
- Xextern FLAG qdigit MATH_PROTO((NUMBER *q, long i));
- Xextern long qprecision MATH_PROTO((NUMBER *q));
- Xextern long qplaces MATH_PROTO((NUMBER *q));
- Xextern long qdigits MATH_PROTO((NUMBER *q));
- Xextern HASH qhash MATH_PROTO((NUMBER *q));
- Xextern void setepsilon MATH_PROTO((NUMBER *q));
- X
- X#if 0
- Xextern NUMBER *qbitvalue MATH_PROTO((long i));
- Xextern NUMBER *qmulmod MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *q3));
- Xextern NUMBER *qsquaremod MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern NUMBER *qaddmod MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *q3));
- Xextern NUMBER *qsubmod MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *q3));
- Xextern NUMBER *qreadval MATH_PROTO((FILE *fp));
- Xextern NUMBER *qnegmod MATH_PROTO((NUMBER *q1, NUMBER *q2));
- Xextern BOOL qbittest MATH_PROTO((NUMBER *q, long i));
- Xextern FLAG qtest MATH_PROTO((NUMBER *q));
- X#endif
- X
- X
- X/*
- X * Transcendental functions. These all take an epsilon argument to
- X * specify the required accuracy of the calculation.
- X */
- Xextern NUMBER *qsqrt MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qpower MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *epsilon));
- Xextern NUMBER *qroot MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *epsilon));
- Xextern NUMBER *qcos MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qsin MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qexp MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qln MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qtan MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qacos MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qasin MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qatan MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qatan2 MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *epsilon));
- Xextern NUMBER *qhypot MATH_PROTO((NUMBER *q1, NUMBER *q2, NUMBER *epsilon));
- Xextern NUMBER *qcosh MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qsinh MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qtanh MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qacosh MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qasinh MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qatanh MATH_PROTO((NUMBER *q, NUMBER *epsilon));
- Xextern NUMBER *qlegtoleg MATH_PROTO((NUMBER *q, NUMBER *epsilon, BOOL wantneg));
- Xextern NUMBER *qpi MATH_PROTO((NUMBER *epsilon));
- X
- X
- X/*
- X * macro expansions to speed this thing up
- X */
- X#define qiszero(q) (ziszero((q)->num))
- X#define qisneg(q) (zisneg((q)->num))
- X#define qispos(q) (zispos((q)->num))
- X#define qisint(q) (zisunit((q)->den))
- X#define qisfrac(q) (!zisunit((q)->den))
- X#define qisunit(q) (zisunit((q)->num) && zisunit((q)->den))
- X#define qisone(q) (zisone((q)->num) && zisunit((q)->den))
- X#define qisnegone(q) (zisnegone((q)->num) && zisunit((q)->den))
- X#define qistwo(q) (zistwo((q)->num) && zisunit((q)->den))
- X#define qiseven(q) (zisunit((q)->den) && ziseven((q)->num))
- X#define qisodd(q) (zisunit((q)->den) && zisodd((q)->num))
- X#define qistwopower(q) (zisunit((q)->den) && zistwopower((q)->num))
- X
- X#define qhighbit(q) (zhighbit((q)->num))
- X#define qlowbit(q) (zlowbit((q)->num))
- X#define qdivcount(q1, q2) (zdivcount((q1)->num, (q2)->num))
- X#define qilog(q1, q2) (zlog((q1)->num, (q2)->num))
- X#define qlink(q) ((q)->links++, (q))
- X
- X#define qfree(q) {if (--((q)->links) <= 0) qfreenum(q);}
- X
- X
- X/*
- X * Flags for qparse calls
- X */
- X#define QPF_SLASH 0x1 /* allow slash for fractional number */
- X#define QPF_IMAG 0x2 /* allow trailing 'i' for imaginary number */
- X
- X
- X#ifdef VARARGS
- Xextern void qprintf();
- X#else
- Xextern void qprintf MATH_PROTO((char *, ...));
- X#endif
- X
- X
- X/*
- X * constants used often by the arithmetic routines
- X */
- Xextern NUMBER _qzero_, _qone_, _qnegone_, _qonehalf_;
- Xextern BOOL _sinisneg_; /* whether sin(x) < 0 (set by cos(x)) */
- Xextern long _epsilonprec_; /* binary precision of epsilon */
- Xextern NUMBER *_epsilon_; /* default error for real functions */
- Xextern long _outdigits_; /* current output digits for float or exp */
- Xextern int _outmode_; /* current output mode */
- X
- X#endif
- X
- X/* END CODE */
- SHAR_EOF
- chmod 0644 calc2.9.0/qmath.h || echo "restore of calc2.9.0/qmath.h fails"
- set `wc -c calc2.9.0/qmath.h`;Sum=$1
- if test "$Sum" != "9457"
- then echo original size 9457, current size $Sum;fi
- echo "x - extracting calc2.9.0/qmod.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/qmod.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 * Modular arithmetic routines for normal numbers, and also using
- X * the faster REDC algorithm.
- X */
- X
- X#include "qmath.h"
- X
- X
- X/*
- X * Structure used for caching REDC information.
- X */
- Xtypedef struct {
- X NUMBER *num; /* modulus being cached */
- X REDC *redc; /* REDC information for modulus */
- X long age; /* age counter for reallocation */
- X} REDC_CACHE;
- X
- X
- Xstatic long redc_age; /* current age counter */
- Xstatic REDC_CACHE redc_cache[MAXREDC]; /* cached REDC info */
- X
- X
- Xstatic REDC *qfindredc MATH_PROTO((NUMBER *q));
- X
- X
- X/*
- X * Return the remainder when one number is divided by another.
- X * The second argument cannot be negative. The result is normalized
- X * to lie in the range 0 to q2, and works for fractional values as:
- X * qmod(q1, q2) = q1 - (int(q1 / q2) * q2).
- X */
- XNUMBER *
- Xqmod(q1, q2)
- X register NUMBER *q1, *q2;
- X{
- X ZVALUE res;
- X NUMBER *q, *tmp;
- X
- X if (qisneg(q2) || qiszero(q2))
- X math_error("Non-positive modulus");
- X if (qisint(q1) && qisint(q2)) { /* easy case */
- X zmod(q1->num, q2->num, &res);
- X if (ziszero(res)) {
- X zfree(res);
- X return qlink(&_qzero_);
- X }
- X if (zisone(res)) {
- X zfree(res);
- X return qlink(&_qone_);
- X }
- X q = qalloc();
- X q->num = res;
- X return q;
- X }
- X q = qquo(q1, q2);
- X tmp = qmul(q, q2);
- X qfree(q);
- X q = qsub(q1, tmp);
- X qfree(tmp);
- X if (qisneg(q)) {
- X tmp = qadd(q2, q);
- X qfree(q);
- X q = tmp;
- X }
- X return q;
- X}
- X
- X
- X/*
- X * Given two numbers (a and b), calculate the quotient (c) and remainder (d)
- X * when a is divided by b. This is defined so 0 <= d < b, and c is integral,
- X * and a = b * c + d. The results are returned indirectly through pointers.
- X * This works for integers or fractions. Returns whether or not there is a
- X * remainder. Examples:
- X * qquomod(11, 4, &x, &y) sets x to 2, y to 3, and returns TRUE.
- X * qquomod(-7, 3, &x, &y) sets x to -3, y to 2, and returns TRUE.
- X */
- XBOOL
- Xqquomod(q1, q2, retqdiv, retqmod)
- X NUMBER *q1, *q2; /* numbers to do quotient with */
- X NUMBER **retqdiv; /* returned quotient */
- X NUMBER **retqmod; /* returned modulo */
- X{
- X NUMBER *qq, *qm, *tmp;
- X
- X if (qisneg(q2) || qiszero(q2))
- X math_error("Non-positive modulus");
- X
- X if (qisint(q1) && qisint(q2)) { /* integer case */
- X qq = qalloc();
- X qm = qalloc();
- X zdiv(q1->num, q2->num, &qq->num, &qm->num);
- X if (!qisneg(q1) || qiszero(qm)) {
- X *retqdiv = qq;
- X *retqmod = qm;
- X return !qiszero(qm);
- X }
- X
- X /*
- X * Need to fix up negative results.
- X */
- X tmp = qdec(qq);
- X qfree(qq);
- X qq = tmp;
- X tmp = qsub(q2, qm);
- X qfree(qm);
- X qm = tmp;
- X *retqdiv = qq;
- X *retqmod = qm;
- X return TRUE;
- X }
- X
- X /*
- X * Fractional case.
- X */
- X qq = qquo(q1, q2);
- X tmp = qmul(qq, q2);
- X qm = qsub(q1, tmp);
- X qfree(tmp);
- X if (qisneg(qm)) {
- X tmp = qadd(qm, q2);
- X qfree(qm);
- X qm = tmp;
- X tmp = qdec(qq);
- X qfree(qq);
- X qq = tmp;
- X }
- X *retqdiv = qq;
- X *retqmod = qm;
- X return !qiszero(qm);
- X}
- X
- X
- X#if 0
- X/*
- X * Return the product of two integers modulo a third integer.
- X * The result is in the range 0 to q3 - 1 inclusive.
- X * q4 = (q1 * q2) mod q3.
- X */
- XNUMBER *
- Xqmulmod(q1, q2, q3)
- X NUMBER *q1, *q2, *q3;
- X{
- X NUMBER *q;
- X
- X if (qisneg(q3) || qiszero(q3))
- X math_error("Non-positive modulus");
- X if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
- X math_error("Non-integers for qmulmod");
- X if (qiszero(q1) || qiszero(q2) || qisunit(q3))
- X return qlink(&_qzero_);
- X q = qalloc();
- X zmulmod(q1->num, q2->num, q3->num, &q->num);
- X return q;
- X}
- X
- X
- X/*
- X * Return the square of an integer modulo another integer.
- X * The result is in the range 0 to q2 - 1 inclusive.
- X * q2 = (q1^2) mod q2.
- X */
- XNUMBER *
- Xqsquaremod(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X NUMBER *q;
- X
- X if (qisneg(q2) || qiszero(q2))
- X math_error("Non-positive modulus");
- X if (qisfrac(q1) || qisfrac(q2))
- X math_error("Non-integers for qsquaremod");
- X if (qiszero(q1) || qisunit(q2))
- X return qlink(&_qzero_);
- X if (qisunit(q1))
- X return qlink(&_qone_);
- X q = qalloc();
- X zsquaremod(q1->num, q2->num, &q->num);
- X return q;
- X}
- X
- X
- X/*
- X * Return the sum of two integers modulo a third integer.
- X * The result is in the range 0 to q3 - 1 inclusive.
- X * q4 = (q1 + q2) mod q3.
- X */
- XNUMBER *
- Xqaddmod(q1, q2, q3)
- X NUMBER *q1, *q2, *q3;
- X{
- X NUMBER *q;
- X
- X if (qisneg(q3) || qiszero(q3))
- X math_error("Non-positive modulus");
- X if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
- X math_error("Non-integers for qaddmod");
- X q = qalloc();
- X zaddmod(q1->num, q2->num, q3->num, &q->num);
- X return q;
- X}
- X
- X
- X/*
- X * Return the difference of two integers modulo a third integer.
- X * The result is in the range 0 to q3 - 1 inclusive.
- X * q4 = (q1 - q2) mod q3.
- X */
- XNUMBER *
- Xqsubmod(q1, q2, q3)
- X NUMBER *q1, *q2, *q3;
- X{
- X NUMBER *q;
- X
- X if (qisneg(q3) || qiszero(q3))
- X math_error("Non-positive modulus");
- X if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
- X math_error("Non-integers for qsubmod");
- X if (q1 == q2)
- X return qlink(&_qzero_);
- X q = qalloc();
- X zsubmod(q1->num, q2->num, q3->num, &q->num);
- X return q;
- X}
- X
- X
- X/*
- X * Return the negative of an integer modulo another integer.
- X * The result is in the range 0 to q2 - 1 inclusive.
- X * q2 = (-q1) mod q2.
- X */
- XNUMBER *
- Xqnegmod(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X NUMBER *q;
- X
- X if (qisneg(q2) || qiszero(q2))
- X math_error("Non-positive modulus");
- X if (qisfrac(q1) || qisfrac(q2))
- X math_error("Non-integers for qnegmod");
- X if (qiszero(q1) || qisunit(q2))
- X return qlink(&_qzero_);
- X q = qalloc();
- X znegmod(q1->num, q2->num, &q->num);
- X return q;
- X}
- X#endif
- X
- X
- X/*
- X * Return the integer congruent to an integer whose absolute value is smallest.
- X * This is a unique integer in the range int((q2-1)/2 to int(q2/2), inclusive.
- X * For example, for a modulus of 7, returned values are [-3, 3], and for a
- X * modulus of 8, returned values are [-3, 4].
- X */
- XNUMBER *
- Xqminmod(q1, q2)
- X NUMBER *q1, *q2;
- X{
- X NUMBER *q;
- X
- X if (qisneg(q2) || qiszero(q2))
- X math_error("Non-positive modulus");
- X if (qisfrac(q1) || qisfrac(q2))
- X math_error("Non-integers for qminmod");
- X if (qiszero(q1) || (q1->num.len < q2->num.len - 1))
- X return qlink(q1);
- X q = qalloc();
- X zminmod(q1->num, q2->num, &q->num);
- X return q;
- X}
- X
- X
- X/*
- X * Return whether or not two integers are congruent modulo a third integer.
- X * Returns TRUE if the numbers are not congruent, and FALSE if they are.
- X */
- XBOOL
- Xqcmpmod(q1, q2, q3)
- X NUMBER *q1, *q2, *q3;
- X{
- X if (qisneg(q3) || qiszero(q3))
- X math_error("Non-positive modulus");
- X if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
- X math_error("Non-integers for qcmpmod");
- X if (q1 == q2)
- X return FALSE;
- X return zcmpmod(q1->num, q2->num, q3->num);
- X}
- X
- X
- X/*
- X * Convert an integer into REDC format for use in faster modular arithmetic.
- X * The number can be negative or out of modulus range.
- X */
- XNUMBER *
- Xqredcin(q1, q2)
- X NUMBER *q1; /* number to convert into REDC format */
- X NUMBER *q2; /* modulus */
- X{
- X REDC *rp; /* REDC information */
- X NUMBER *r; /* result */
- X
- X if (qisfrac(q1))
- X math_error("Non-integer for qredcin");
- X rp = qfindredc(q2);
- X if (qiszero(q1))
- X return qlink(&_qzero_);
- X r = qalloc();
- X zredcencode(rp, q1->num, &r->num);
- X return r;
- X}
- X
- X
- X/*
- X * Convert a REDC format number back into a normal integer.
- X * The resulting number is in the range 0 to the modulus - 1.
- X */
- XNUMBER *
- Xqredcout(q1, q2)
- X NUMBER *q1; /* number to convert out of REDC format */
- X NUMBER *q2; /* modulus */
- X{
- X REDC *rp; /* REDC information */
- X NUMBER *r; /* result */
- X
- X if (qisfrac(q1) || qisneg(q1))
- X math_error("Non-positive integer required for qredcout");
- X rp = qfindredc(q2);
- X if (qiszero(q1))
- X return qlink(&_qzero_);
- X r = qalloc();
- X zredcdecode(rp, q1->num, &r->num);
- X if (zisunit(r->num)) {
- X qfree(r);
- X r = qlink(&_qone_);
- X }
- X return r;
- X}
- X
- X
- X/*
- X * Multiply two REDC format numbers together producing a REDC format result.
- X * This multiplication is done modulo the specified modulus.
- X */
- XNUMBER *
- Xqredcmul(q1, q2, q3)
- X NUMBER *q1, *q2; /* REDC numbers to be multiplied */
- X NUMBER *q3; /* modulus */
- X{
- X REDC *rp; /* REDC information */
- X NUMBER *r; /* result */
- X
- X if (qisfrac(q1) || qisneg(q1) || qisfrac(q2) || qisneg(q2))
- X math_error("Non-positive integers required for qredcmul");
- X rp = qfindredc(q3);
- X if (qiszero(q1) || qiszero(q2))
- X return qlink(&_qzero_);
- X r = qalloc();
- X zredcmul(rp, q1->num, q2->num, &r->num);
- X return r;
- X}
- X
- X
- X/*
- X * Square a REDC format number to produce a REDC format result.
- X * This squaring is done modulo the specified modulus.
- X */
- XNUMBER *
- Xqredcsquare(q1, q2)
- X NUMBER *q1; /* REDC number to be squared */
- X NUMBER *q2; /* modulus */
- X{
- X REDC *rp; /* REDC information */
- X NUMBER *r; /* result */
- X
- X if (qisfrac(q1) || qisneg(q1))
- X math_error("Non-positive integer required for qredcsquare");
- X rp = qfindredc(q2);
- X if (qiszero(q1))
- X return qlink(&_qzero_);
- X r = qalloc();
- X zredcsquare(rp, q1->num, &r->num);
- X return r;
- X}
- X
- X
- X/*
- X * Raise a REDC format number to the indicated power producing a REDC
- X * format result. This is done modulo the specified modulus. The
- X * power to be raised to is a normal number.
- X */
- XNUMBER *
- Xqredcpower(q1, q2, q3)
- X NUMBER *q1; /* REDC number to be raised */
- X NUMBER *q2; /* power to be raised to */
- X NUMBER *q3; /* modulus */
- X{
- X REDC *rp; /* REDC information */
- X NUMBER *r; /* result */
- X
- X if (qisfrac(q1) || qisneg(q1) || qisfrac(q2) || qisneg(q2))
- X math_error("Non-positive integers required for qredcpower");
- X rp = qfindredc(q3);
- X if (qiszero(q1) || qisunit(q3))
- X return qlink(&_qzero_);
- X r = qalloc();
- X zredcpower(rp, q1->num, q2->num, &r->num);
- X return r;
- X}
- X
- X
- X/*
- X * Search for and return the REDC information for the specified number.
- X * The information is cached into a local table so that future calls
- X * for this information will be quick. If the table fills up, then
- X * the oldest cached entry is reused.
- X */
- Xstatic REDC *
- Xqfindredc(q)
- X NUMBER *q; /* modulus to find REDC information of */
- X{
- X register REDC_CACHE *rcp;
- X REDC_CACHE *bestrcp;
- X
- X /*
- X * First try for an exact pointer match in the table.
- X */
- X for (rcp = redc_cache; rcp < &redc_cache[MAXREDC]; rcp++) {
- X if (q == rcp->num) {
- X rcp->age = ++redc_age;
- X return rcp->redc;
- X }
- X }
- X
- X /*
- X * Search the table again looking for a value which matches.
- X */
- X for (rcp = redc_cache; rcp < &redc_cache[MAXREDC]; rcp++) {
- X if (rcp->age && (qcmp(q, rcp->num) == 0)) {
- X rcp->age = ++redc_age;
- X return rcp->redc;
- X }
- X }
- X
- X /*
- X * Must invalidate an existing entry in the table.
- X * Find the oldest (or first unused) entry.
- X * But first make sure the modulus will be reasonable.
- X */
- X if (qisfrac(q) || qiseven(q) || qisneg(q))
- X math_error("REDC modulus must be positive odd integer");
- X
- X bestrcp = NULL;
- X for (rcp = redc_cache; rcp < &redc_cache[MAXREDC]; rcp++) {
- X if ((bestrcp == NULL) || (rcp->age < bestrcp->age))
- X bestrcp = rcp;
- X }
- X
- X /*
- X * Found the best entry.
- X * Free the old information for the entry if necessary,
- X * then initialize it.
- X */
- X rcp = bestrcp;
- X if (rcp->age) {
- X rcp->age = 0;
- X qfree(rcp->num);
- X zredcfree(rcp->redc);
- X }
- X
- X rcp->redc = zredcalloc(q->num);
- X rcp->num = qlink(q);
- X rcp->age = ++redc_age;
- X return rcp->redc;
- X}
- X
- X/* END CODE */
- SHAR_EOF
- chmod 0644 calc2.9.0/qmod.c || echo "restore of calc2.9.0/qmod.c fails"
- set `wc -c calc2.9.0/qmod.c`;Sum=$1
- if test "$Sum" != "10958"
- then echo original size 10958, current size $Sum;fi
- echo "x - extracting calc2.9.0/qtrans.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/qtrans.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 * Transcendental functions for real numbers.
- X * These are sin, cos, exp, ln, power, cosh, sinh.
- X */
- X
- X#include "qmath.h"
- X
- XBOOL _sinisneg_; /* whether sin(x) < 0 (set by cos(x)) */
- X
- X
- X/*
- X * Calculate the cosine of a number with an accuracy within epsilon.
- X * This also saves the sign of the corresponding sin function.
- X */
- XNUMBER *
- Xqcos(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *term, *sum, *qsq, *epsilon2, *tmp;
- X FULL n, i;
- X long scale, bits, bits2;
- X
- X _sinisneg_ = qisneg(q);
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for cosine");
- X if (qiszero(q))
- X return qlink(&_qone_);
- X bits = qprecision(epsilon) + 1;
- X epsilon = qscale(epsilon, -4L);
- X /*
- X * If the argument is larger than one, then divide it by a power of two
- X * so that it is one or less. This will make the series converge quickly.
- X * We will extrapolate the result for the original argument afterwards.
- X */
- X scale = zhighbit(q->num) - zhighbit(q->den) + 1;
- X if (scale < 0)
- X scale = 0;
- X if (scale > 0) {
- X q = qscale(q, -scale);
- X tmp = qscale(epsilon, -scale);
- X qfree(epsilon);
- X epsilon = tmp;
- X }
- X epsilon2 = qscale(epsilon, -4L);
- X qfree(epsilon);
- X bits2 = qprecision(epsilon2) + 10;
- X /*
- X * Now use the Taylor series expansion to calculate the cosine.
- X * Keep using approximations so that the fractions don't get too large.
- X */
- X qsq = qsquare(q);
- X if (scale > 0)
- X qfree(q);
- X term = qlink(&_qone_);
- X sum = qlink(&_qone_);
- X n = 0;
- X while (qrel(term, epsilon2) > 0) {
- X i = ++n;
- X i *= ++n;
- X tmp = qmul(term, qsq);
- X qfree(term);
- X term = qdivi(tmp, (long) i);
- X qfree(tmp);
- X tmp = qbround(term, bits2);
- X qfree(term);
- X term = tmp;
- X if (n & 2)
- X tmp = qsub(sum, term);
- X else
- X tmp = qadd(sum, term);
- X qfree(sum);
- X sum = qbround(tmp, bits2);
- X qfree(tmp);
- X }
- X qfree(term);
- X qfree(qsq);
- X qfree(epsilon2);
- X /*
- X * Now scale back up to the original value of x by using the formula:
- X * cos(2 * x) = 2 * (cos(x) ^ 2) - 1.
- X */
- X while (--scale >= 0) {
- X if (qisneg(sum))
- X _sinisneg_ = !_sinisneg_;
- X tmp = qsquare(sum);
- X qfree(sum);
- X sum = qscale(tmp, 1L);
- X qfree(tmp);
- X tmp = qdec(sum);
- X qfree(sum);
- X sum = qbround(tmp, bits2);
- X qfree(tmp);
- X }
- X tmp = qbround(sum, bits);
- X qfree(sum);
- X return tmp;
- X}
- X
- X
- X/*
- X * Calculate the sine of a number with an accuracy within epsilon.
- X * This is calculated using the formula:
- X * sin(x)^2 + cos(x)^2 = 1.
- X * The only tricky bit is resolving the sign of the result.
- X * Future: Use sin(3*x) = 3*sin(x) - 4*sin(x)^3.
- X */
- XNUMBER *
- Xqsin(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *epsilon2;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for sine");
- X if (qiszero(q))
- X return qlink(q);
- X epsilon2 = qsquare(epsilon);
- X tmp1 = qcos(q, epsilon2);
- X qfree(epsilon2);
- X tmp2 = qlegtoleg(tmp1, epsilon, _sinisneg_);
- X qfree(tmp1);
- X return tmp2;
- X}
- X
- X
- X/*
- X * Calculate the tangent function.
- X */
- XNUMBER *
- Xqtan(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *cosval, *sinval, *epsilon2, *tmp, *res;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for tangent");
- X if (qiszero(q))
- X return qlink(q);
- X epsilon2 = qsquare(epsilon);
- X cosval = qcos(q, epsilon2);
- X sinval = qlegtoleg(cosval, epsilon2, _sinisneg_);
- X qfree(epsilon2);
- X tmp = qdiv(sinval, cosval);
- X qfree(cosval);
- X qfree(sinval);
- X res = qbround(tmp, qprecision(epsilon) + 1);
- X qfree(tmp);
- X return res;
- X}
- X
- X
- X/*
- X * Calculate the arcsine function.
- X * The result is in the range -pi/2 to pi/2.
- X */
- XNUMBER *
- Xqasin(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *sum, *term, *epsilon2, *qsq, *tmp;
- X FULL n, i;
- X long bits, bits2;
- X int neg;
- X NUMBER mulnum;
- X HALF numval[2];
- X HALF denval[2];
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for arcsine");
- X if (qiszero(q))
- X return qlink(&_qzero_);
- X if ((qrel(q, &_qone_) > 0) || (qrel(q, &_qnegone_) < 0))
- X math_error("Argument too large for asin");
- X neg = qisneg(q);
- X q = qabs(q);
- X epsilon = qscale(epsilon, -4L);
- X epsilon2 = qscale(epsilon, -4L);
- X mulnum.num.sign = 0;
- X mulnum.num.len = 1;
- X mulnum.num.v = numval;
- X mulnum.den.sign = 0;
- X mulnum.den.len = 1;
- X mulnum.den.v = denval;
- X /*
- X * If the argument is too near one (we use .5) then reduce the
- X * argument to a more accurate range using the formula:
- X * asin(x) = 2 * asin(sqrt((1 - sqrt(1 - x^2)) / 2)).
- X */
- X if (qrel(q, &_qonehalf_) > 0) {
- X sum = qlegtoleg(q, epsilon2, FALSE);
- X qfree(q);
- X tmp = qsub(&_qone_, sum);
- X qfree(sum);
- X sum = qscale(tmp, -1L);
- X qfree(tmp);
- X tmp = qsqrt(sum, epsilon2);
- X qfree(sum);
- X qfree(epsilon2);
- X sum = qasin(tmp, epsilon);
- X qfree(tmp);
- X qfree(epsilon);
- X tmp = qscale(sum, 1L);
- X qfree(sum);
- X if (neg) {
- X sum = qneg(tmp);
- X qfree(tmp);
- X tmp = sum;
- X }
- X return tmp;
- X }
- X /*
- X * Argument is between zero and .5, so use the series.
- X */
- X epsilon = qscale(epsilon, -4L);
- X epsilon2 = qscale(epsilon, -4L);
- X bits = qprecision(epsilon) + 1;
- X bits2 = bits + 10;
- X sum = qlink(q);
- X term = qlink(q);
- X qsq = qsquare(q);
- X qfree(q);
- X n = 1;
- X while (qrel(term, epsilon2) > 0) {
- X i = n * n;
- X numval[0] = i & BASE1;
- X if (i >= BASE) {
- X numval[1] = i / BASE;
- X mulnum.den.len = 2;
- X }
- X i = (n + 1) * (n + 2);
- X denval[0] = i & BASE1;
- X if (i >= BASE) {
- X denval[1] = i / BASE;
- X mulnum.den.len = 2;
- X }
- X tmp = qmul(term, qsq);
- X qfree(term);
- X term = qmul(tmp, &mulnum);
- X qfree(tmp);
- X tmp = qbround(term, bits2);
- X qfree(term);
- X term = tmp;
- X tmp = qadd(sum, term);
- X qfree(sum);
- X sum = qbround(tmp, bits2);
- X qfree(tmp);
- X n += 2;
- X }
- X qfree(epsilon);
- X qfree(epsilon2);
- X qfree(term);
- X qfree(qsq);
- X tmp = qbround(sum, bits);
- X qfree(sum);
- X if (neg) {
- X term = qneg(tmp);
- X qfree(tmp);
- X tmp = term;
- X }
- X return tmp;
- X}
- X
- X
- X/*
- X * Calculate the acos function.
- X * The result is in the range 0 to pi.
- X */
- XNUMBER *
- Xqacos(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *tmp3, *epsilon2;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for arccosine");
- X if (qisone(q))
- X return qlink(&_qzero_);
- X if ((qrel(q, &_qone_) > 0) || (qrel(q, &_qnegone_) < 0))
- X math_error("Argument too large for acos");
- X /*
- X * Calculate the result using the formula:
- X * acos(x) = asin(sqrt(1 - x^2)).
- X * The formula is only good for positive x, so we must fix up the
- X * result for negative values.
- X */
- X epsilon2 = qscale(epsilon, -8L);
- X tmp1 = qlegtoleg(q, epsilon2, FALSE);
- X qfree(epsilon2);
- X tmp2 = qasin(tmp1, epsilon);
- X qfree(tmp1);
- X if (!qisneg(q))
- X return tmp2;
- X /*
- X * For negative values, we need to subtract the asin from pi.
- X */
- X tmp1 = qpi(epsilon);
- X tmp3 = qsub(tmp1, tmp2);
- X qfree(tmp1);
- X qfree(tmp2);
- X tmp1 = qbround(tmp3, qprecision(epsilon) + 1);
- X qfree(tmp3);
- X return tmp1;
- X}
- X
- X
- X/*
- X * Calculate the arctangent function with a accuracy less than epsilon.
- X * This uses the formula:
- X * atan(x) = asin(sqrt(x^2 / (x^2 + 1))).
- X */
- XNUMBER *
- Xqatan(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *tmp3, *epsilon2;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for arctangent");
- X if (qiszero(q))
- X return qlink(&_qzero_);
- X tmp1 = qsquare(q);
- X tmp2 = qinc(tmp1);
- X tmp3 = qdiv(tmp1, tmp2);
- X qfree(tmp1);
- X qfree(tmp2);
- X epsilon2 = qscale(epsilon, -8L);
- X tmp1 = qsqrt(tmp3, epsilon2);
- X qfree(epsilon2);
- X qfree(tmp3);
- X tmp2 = qasin(tmp1, epsilon);
- X qfree(tmp1);
- X if (qisneg(q)) {
- X tmp1 = qneg(tmp2);
- X qfree(tmp2);
- X tmp2 = tmp1;
- X }
- X return tmp2;
- X}
- X
- X
- X/*
- X * Calculate the angle which is determined by the point (x,y).
- X * This is the same as arctan for non-negative x, but gives the correct
- X * value for negative x. By convention, y is the first argument.
- X * For example, qatan2(1, -1) = 3/4 * pi.
- X */
- XNUMBER *
- Xqatan2(qy, qx, epsilon)
- X NUMBER *qy, *qx, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *epsilon2;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for atan2");
- X if (qiszero(qy) && qiszero(qx))
- X math_error("Zero coordinates for atan2");
- X /*
- X * If the point is on the negative real axis, then the answer is pi.
- X */
- X if (qiszero(qy) && qisneg(qx))
- X return qpi(epsilon);
- X /*
- X * If the point is in the right half plane, then use the normal atan.
- X */
- X if (!qisneg(qx) && !qiszero(qx)) {
- X if (qiszero(qy))
- X return qlink(&_qzero_);
- X tmp1 = qdiv(qy, qx);
- X tmp2 = qatan(tmp1, epsilon);
- X qfree(tmp1);
- X return tmp2;
- X }
- X /*
- X * The point is in the left half plane. Calculate the angle by finding
- X * the atan of half the angle using the formula:
- X * atan2(y,x) = 2 * atan((sqrt(x^2 + y^2) - x) / y).
- X */
- X epsilon2 = qscale(epsilon, -4L);
- X tmp1 = qhypot(qx, qy, epsilon2);
- X tmp2 = qsub(tmp1, qx);
- X qfree(tmp1);
- X tmp1 = qdiv(tmp2, qy);
- X qfree(tmp2);
- X tmp2 = qatan(tmp1, epsilon2);
- X qfree(tmp1);
- X qfree(epsilon2);
- X tmp1 = qscale(tmp2, 1L);
- X qfree(tmp2);
- X return tmp1;
- X}
- X
- X
- X/*
- X * Calculate the value of pi to within the required epsilon.
- X * This uses the following formula which only needs integer calculations
- X * except for the final operation:
- X * pi = 1 / SUMOF(comb(2 * N, N) ^ 3 * (42 * N + 5) / 2 ^ (12 * N + 4)),
- X * where the summation runs from N=0. This formula gives about 6 bits of
- X * accuracy per term. Since the denominator for each term is a power of two,
- X * we can simply use shifts to sum the terms. The combinatorial numbers
- X * in the formula are calculated recursively using the formula:
- X * comb(2*(N+1), N+1) = 2 * comb(2 * N, N) * (2 * N + 1) / N.
- X */
- XNUMBER *
- Xqpi(epsilon)
- X NUMBER *epsilon;
- X{
- X ZVALUE comb; /* current combinatorial value */
- X ZVALUE sum; /* current sum */
- X ZVALUE tmp1, tmp2;
- X NUMBER *r, *t1, qtmp;
- X long shift; /* current shift of result */
- X long N; /* current term number */
- X long bits; /* needed number of bits of precision */
- X long t;
- X
- X if (qiszero(epsilon) || qisneg(epsilon))
- X math_error("Bad epsilon value for pi");
- X bits = qprecision(epsilon) + 4;
- X comb = _one_;
- X itoz(5L, &sum);
- X N = 0;
- X shift = 4;
- X do {
- X t = 1 + (++N & 0x1);
- X (void) zdivi(comb, N / (3 - t), &tmp1);
- X zfree(comb);
- X zmuli(tmp1, t * (2 * N - 1), &comb);
- X zfree(tmp1);
- X zsquare(comb, &tmp1);
- X zmul(comb, tmp1, &tmp2);
- X zfree(tmp1);
- X zmuli(tmp2, 42 * N + 5, &tmp1);
- X zfree(tmp2);
- X zshift(sum, 12L, &tmp2);
- X zfree(sum);
- X zadd(tmp1, tmp2, &sum);
- X t = zhighbit(tmp1);
- X zfree(tmp1);
- X zfree(tmp2);
- X shift += 12;
- X } while ((shift - t) < bits);
- X qtmp.num = _one_;
- X qtmp.den = sum;
- X t1 = qscale(&qtmp, shift);
- X zfree(sum);
- X r = qbround(t1, bits);
- X qfree(t1);
- X return r;
- X}
- X
- X
- X/*
- X * Calculate the exponential function with a relative accuracy less than
- X * epsilon.
- X */
- XNUMBER *
- Xqexp(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X long scale;
- X FULL n;
- X long bits, bits2;
- X NUMBER *sum, *term, *qs, *epsilon2, *tmp;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for exp");
- X if (qiszero(q))
- X return qlink(&_qone_);
- X epsilon = qscale(epsilon, -4L);
- X /*
- X * If the argument is larger than one, then divide it by a power of two
- X * so that it is one or less. This will make the series converge quickly.
- X * We will extrapolate the result for the original argument afterwards.
- X * Also make the argument non-negative.
- X */
- X qs = qabs(q);
- X scale = zhighbit(q->num) - zhighbit(q->den) + 1;
- X if (scale < 0)
- X scale = 0;
- X if (scale > 0) {
- X if (scale > 100000)
- X math_error("Very large argument for exp");
- X tmp = qscale(qs, -scale);
- X qfree(qs);
- X qs = tmp;
- X tmp = qscale(epsilon, -scale);
- X qfree(epsilon);
- X epsilon = tmp;
- X }
- X epsilon2 = qscale(epsilon, -4L);
- X bits = qprecision(epsilon) + 1;
- X bits2 = bits + 10;
- X qfree(epsilon);
- X /*
- X * Now use the Taylor series expansion to calculate the exponential.
- X * Keep using approximations so that the fractions don't get too large.
- X */
- X sum = qlink(&_qone_);
- X term = qlink(&_qone_);
- X n = 0;
- X while (qrel(term, epsilon2) > 0) {
- X n++;
- X tmp = qmul(term, qs);
- X qfree(term);
- X term = qdivi(tmp, (long) n);
- X qfree(tmp);
- X tmp = qbround(term, bits2);
- X qfree(term);
- X term = tmp;
- X tmp = qadd(sum, term);
- X qfree(sum);
- X sum = qbround(tmp, bits2);
- X qfree(tmp);
- X }
- X qfree(term);
- X qfree(qs);
- X qfree(epsilon2);
- X /*
- X * Now repeatedly square the answer to get the final result.
- X * Then invert it if the original argument was negative.
- X */
- X while (--scale >= 0) {
- X tmp = qsquare(sum);
- X qfree(sum);
- X sum = qbround(tmp, bits2);
- X qfree(tmp);
- X }
- X tmp = qbround(sum, bits);
- X qfree(sum);
- X if (qisneg(q)) {
- X sum = qinv(tmp);
- X qfree(tmp);
- X tmp = sum;
- X }
- X return tmp;
- X}
- X
- X
- X/*
- X * Calculate the natural logarithm of a number accurate to the specified
- X * epsilon.
- X */
- XNUMBER *
- Xqln(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *term, *term2, *sum, *epsilon2, *tmp1, *tmp2, *maxr;
- X long shift, bits, bits2;
- X int j, k;
- X FULL n;
- X BOOL neg;
- X
- X if (qisneg(q) || qiszero(q))
- X math_error("log of non-positive number");
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon for ln");
- X if (qisone(q))
- X return qlink(&_qzero_);
- X /*
- X * If the number is less than one, invert it and remember that
- X * the result is to be negative.
- X */
- X neg = FALSE;
- X if (zrel(q->num, q->den) < 0) {
- X neg = TRUE;
- X q = qinv(q);
- X } else
- X q = qlink(q);
- X j = 16;
- X k = zhighbit(q->num) - zhighbit(q->den) + 1;
- X while (k >>= 1)
- X j++;
- X epsilon2 = qscale(epsilon, -j);
- X bits = qprecision(epsilon) + 1;
- X bits2 = qprecision(epsilon2) + 5;
- X /*
- X * By repeated square-roots scale number down to a value close
- X * to 1 so that Taylor series to be used will converge rapidly.
- X * The effect of scaling will be reversed by a later shift.
- X */
- X maxr = iitoq(65537L, 65536L);
- X shift = 1;
- X while (qrel(q, maxr) > 0) {
- X tmp1 = qsqrt(q, epsilon2);
- X qfree(q);
- X q = tmp1;
- X shift++;
- X }
- X qfree(maxr);
- X /*
- X * Calculate a value which will always converge using the formula:
- X * ln((1+x)/(1-x)) = ln(1+x) - ln(1-x).
- X */
- X tmp1 = qdec(q);
- X tmp2 = qinc(q);
- X term = qdiv(tmp1, tmp2);
- X qfree(tmp1);
- X qfree(tmp2);
- X qfree(q);
- X /*
- X * Now use the Taylor series expansion to calculate the result.
- X */
- X n = 1;
- X term2 = qsquare(term);
- X sum = qlink(term);
- X while (qrel(term, epsilon2) > 0) {
- X n += 2;
- X tmp1 = qmul(term, term2);
- X qfree(term);
- X term = qbround(tmp1, bits2);
- X qfree(tmp1);
- X tmp1 = qdivi(term, (long) n);
- X tmp2 = qadd(sum, tmp1);
- X qfree(tmp1);
- X qfree(sum);
- X sum = qbround(tmp2, bits2);
- X }
- X qfree(epsilon2);
- X qfree(term);
- X qfree(term2);
- X /*
- X * Calculate the final result by multiplying by the proper power
- X * of two to undo the square roots done at the top, and possibly
- X * negating the result.
- X */
- X tmp1 = qscale(sum, shift);
- X qfree(sum);
- X sum = qbround(tmp1, bits);
- X qfree(tmp1);
- X if (neg) {
- X tmp1 = qneg(sum);
- X qfree(sum);
- X sum = tmp1;
- X }
- X return sum;
- X}
- X
- X
- X/*
- X * Calculate the result of raising one number to the power of another.
- X * The result is calculated to within the specified relative error.
- X */
- XNUMBER *
- Xqpower(q1, q2, epsilon)
- X NUMBER *q1, *q2, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *epsilon2;
- X
- X if (qisint(q2))
- X return qpowi(q1, q2);
- X epsilon2 = qscale(epsilon, -4L);
- X tmp1 = qln(q1, epsilon2);
- X tmp2 = qmul(tmp1, q2);
- X qfree(tmp1);
- X tmp1 = qexp(tmp2, epsilon);
- X qfree(tmp2);
- X qfree(epsilon2);
- X return tmp1;
- X}
- X
- X
- X/*
- X * Calculate the Kth root of a number to within the specified accuracy.
- X */
- XNUMBER *
- Xqroot(q1, q2, epsilon)
- X NUMBER *q1, *q2, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *epsilon2;
- X int neg;
- X
- X if (qisneg(q2) || qiszero(q2) || qisfrac(q2))
- X math_error("Taking bad root of number");
- X if (qiszero(q1) || qisone(q1) || qisone(q2))
- X return qlink(q1);
- X if (qistwo(q2))
- X return qsqrt(q1, epsilon);
- X neg = qisneg(q1);
- X if (neg) {
- X if (ziseven(q2->num))
- X math_error("Taking even root of negative number");
- X q1 = qabs(q1);
- X }
- X epsilon2 = qscale(epsilon, -4L);
- X tmp1 = qln(q1, epsilon2);
- X tmp2 = qdiv(tmp1, q2);
- X qfree(tmp1);
- X tmp1 = qexp(tmp2, epsilon);
- X qfree(tmp2);
- X qfree(epsilon2);
- X if (neg) {
- X tmp2 = qneg(tmp1);
- X qfree(tmp1);
- X tmp1 = tmp2;
- X }
- X return tmp1;
- X}
- X
- X
- X/*
- X * Calculate the hyperbolic cosine function with a relative accuracy less
- X * than epsilon. This is defined by:
- X * cosh(x) = (exp(x) + exp(-x)) / 2.
- X */
- XNUMBER *
- Xqcosh(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X long scale;
- X FULL n;
- X FULL m;
- X long bits, bits2;
- X NUMBER *sum, *term, *qs, *epsilon2, *tmp;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for exp");
- X if (qiszero(q))
- X return qlink(&_qone_);
- X epsilon = qscale(epsilon, -4L);
- X /*
- X * If the argument is larger than one, then divide it by a power of two
- X * so that it is one or less. This will make the series converge quickly.
- X * We will extrapolate the result for the original argument afterwards.
- X */
- X qs = qabs(q);
- X scale = zhighbit(q->num) - zhighbit(q->den) + 1;
- X if (scale < 0)
- X scale = 0;
- X if (scale > 0) {
- X if (scale > 100000)
- X math_error("Very large argument for exp");
- X tmp = qscale(qs, -scale);
- X qfree(qs);
- X qs = tmp;
- X tmp = qscale(epsilon, -scale);
- X qfree(epsilon);
- X epsilon = tmp;
- X }
- X epsilon2 = qscale(epsilon, -4L);
- X bits = qprecision(epsilon) + 1;
- X bits2 = bits + 10;
- X qfree(epsilon);
- X tmp = qsquare(qs);
- X qfree(qs);
- X qs = tmp;
- X /*
- X * Now use the Taylor series expansion to calculate the exponential.
- X * Keep using approximations so that the fractions don't get too large.
- X */
- X sum = qlink(&_qone_);
- X term = qlink(&_qone_);
- X n = 0;
- X while (qrel(term, epsilon2) > 0) {
- X m = ++n;
- X m *= ++n;
- X tmp = qmul(term, qs);
- X qfree(term);
- X term = qdivi(tmp, (long) m);
- X qfree(tmp);
- X tmp = qbround(term, bits2);
- X qfree(term);
- X term = tmp;
- X tmp = qadd(sum, term);
- X qfree(sum);
- X sum = qbround(tmp, bits2);
- X qfree(tmp);
- X }
- X qfree(term);
- X qfree(qs);
- X qfree(epsilon2);
- X /*
- X * Now bring the number back up into range to get the final result.
- X * This uses the formula:
- X * cosh(2 * x) = 2 * cosh(x)^2 - 1.
- X */
- X while (--scale >= 0) {
- X tmp = qsquare(sum);
- X qfree(sum);
- X sum = qscale(tmp, 1L);
- X qfree(tmp);
- X tmp = qdec(sum);
- X qfree(sum);
- X sum = qbround(tmp, bits2);
- X qfree(tmp);
- X }
- X tmp = qbround(sum, bits);
- X qfree(sum);
- X return tmp;
- X}
- X
- X
- X/*
- X * Calculate the hyperbolic sine with an accurary less than epsilon.
- X * This is calculated using the formula:
- X * cosh(x)^2 - sinh(x)^2 = 1.
- X */
- XNUMBER *
- Xqsinh(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for sinh");
- X if (qiszero(q))
- X return qlink(q);
- X epsilon = qscale(epsilon, -4L);
- X tmp1 = qcosh(q, epsilon);
- X tmp2 = qsquare(tmp1);
- X qfree(tmp1);
- X tmp1 = qdec(tmp2);
- X qfree(tmp2);
- X tmp2 = qsqrt(tmp1, epsilon);
- X qfree(tmp1);
- X if (qisneg(q)) {
- X tmp1 = qneg(tmp2);
- X qfree(tmp2);
- X tmp2 = tmp1;
- X }
- X qfree(epsilon);
- X return tmp2;
- X}
- X
- X
- X/*
- X * Calculate the hyperbolic tangent with an accurary less than epsilon.
- X * This is calculated using the formula:
- X * tanh(x) = sinh(x) / cosh(x).
- X */
- XNUMBER *
- Xqtanh(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *coshval;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for tanh");
- X if (qiszero(q))
- X return qlink(q);
- X epsilon = qscale(epsilon, -4L);
- X coshval = qcosh(q, epsilon);
- X tmp2 = qsquare(coshval);
- X tmp1 = qdec(tmp2);
- X qfree(tmp2);
- X tmp2 = qsqrt(tmp1, epsilon);
- X qfree(tmp1);
- X if (qisneg(q)) {
- X tmp1 = qneg(tmp2);
- X qfree(tmp2);
- X tmp2 = tmp1;
- X }
- X qfree(epsilon);
- X tmp1 = qdiv(tmp2, coshval);
- X qfree(tmp2);
- X qfree(coshval);
- X return tmp1;
- X}
- X
- X
- X/*
- X * Compute the hyperbolic arccosine within the specified accuracy.
- X * This is calculated using the formula:
- X * acosh(x) = ln(x + sqrt(x^2 - 1)).
- X */
- XNUMBER *
- Xqacosh(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *epsilon2;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for acosh");
- X if (qisone(q))
- X return qlink(&_qzero_);
- X if (qreli(q, 1L) < 0)
- X math_error("Argument less than one for acosh");
- X epsilon2 = qscale(epsilon, -8L);
- X tmp1 = qsquare(q);
- X tmp2 = qdec(tmp1);
- X qfree(tmp1);
- X tmp1 = qsqrt(tmp2, epsilon2);
- X qfree(tmp2);
- X tmp2 = qadd(tmp1, q);
- X qfree(tmp1);
- X tmp1 = qln(tmp2, epsilon);
- X qfree(tmp2);
- X qfree(epsilon2);
- X return tmp1;
- X}
- X
- X
- X/*
- X * Compute the hyperbolic arcsine within the specified accuracy.
- X * This is calculated using the formula:
- X * asinh(x) = ln(x + sqrt(x^2 + 1)).
- X */
- XNUMBER *
- Xqasinh(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *epsilon2;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for asinh");
- X if (qiszero(q))
- X return qlink(&_qzero_);
- X epsilon2 = qscale(epsilon, -8L);
- X tmp1 = qsquare(q);
- X tmp2 = qinc(tmp1);
- X qfree(tmp1);
- X tmp1 = qsqrt(tmp2, epsilon2);
- X qfree(tmp2);
- X tmp2 = qadd(tmp1, q);
- X qfree(tmp1);
- X tmp1 = qln(tmp2, epsilon);
- X qfree(tmp2);
- X qfree(epsilon2);
- X return tmp1;
- X}
- X
- X
- X/*
- X * Compute the hyperbolic arctangent within the specified accuracy.
- X * This is calculated using the formula:
- X * atanh(x) = ln((1 + u) / (1 - u)) / 2.
- X */
- XNUMBER *
- Xqatanh(q, epsilon)
- X NUMBER *q, *epsilon;
- X{
- X NUMBER *tmp1, *tmp2, *tmp3;
- X
- X if (qisneg(epsilon) || qiszero(epsilon))
- X math_error("Illegal epsilon value for atanh");
- X if (qiszero(q))
- X return qlink(&_qzero_);
- X if ((qreli(q, 1L) > 0) || (qreli(q, -1L) < 0))
- X math_error("Argument not between -1 and 1 for atanh");
- X tmp1 = qinc(q);
- X tmp2 = qsub(&_qone_, q);
- X tmp3 = qdiv(tmp1, tmp2);
- X qfree(tmp1);
- X qfree(tmp2);
- X tmp1 = qln(tmp3, epsilon);
- X qfree(tmp3);
- X tmp2 = qscale(tmp1, -1L);
- X qfree(tmp1);
- X return tmp2;
- X}
- X
- X/* END CODE */
- SHAR_EOF
- chmod 0644 calc2.9.0/qtrans.c || echo "restore of calc2.9.0/qtrans.c fails"
- set `wc -c calc2.9.0/qtrans.c`;Sum=$1
- if test "$Sum" != "21232"
- then echo original size 21232, current size $Sum;fi
- echo "x - extracting calc2.9.0/stdarg.h (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/stdarg.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#include "args.h"
- X
- X#ifndef STDARG_H
- X#define STDARG_H
- X
- X#ifdef VARARGS
- X
- X#include <varargs.h>
- X
- X#else /*VARARG*/
- X
- X#ifdef STDARG
- X
- X#if defined(__STDC__)
- X#include <stdarg.h>
- X#else
- X%;%;% BOGUS DEFINE! Must use ANSI C when STDARG is defined %;%;%
- X#endif
- X
- X#else /*STDARG*/
- X
- X/*
- X * SIMULATE_STDARG
- X *
- X * WARNING: This type of stdarg makes assumptions about the stack
- X * that may not be true on your system. You may want to
- X * define STDARG (if using ANSI C) or VARARGS.
- X */
- X
- Xtypedef char *va_list;
- X#define va_start(ap,parmn) (void)((ap) = (char*)(&(parmn) + 1))
- X#define va_end(ap) (void)((ap) = 0)
- X#define va_arg(ap, type) \
- X (((type*)((ap) = ((ap) + sizeof(type))))[-1])
- X
- X#endif /*STDARG*/
- X#endif /*VARARG*/
- X
- X#endif
- X
- X/* END CODE */
- SHAR_EOF
- chmod 0644 calc2.9.0/stdarg.h || echo "restore of calc2.9.0/stdarg.h fails"
- set `wc -c calc2.9.0/stdarg.h`;Sum=$1
- if test "$Sum" != "904"
- then echo original size 904, current size $Sum;fi
- echo "x - extracting calc2.9.0/string.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/string.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 * String list routines.
- X */
- X
- X#include "calc.h"
- X#include "string.h"
- X
- X#define STR_TABLECHUNK 100 /* how often to reallocate string table */
- X#define STR_CHUNK 2000 /* size of string storage allocation */
- X#define STR_UNIQUE 100 /* size of string to allocate separately */
- X
- X
- Xstatic char *chartable; /* single character string table */
- X
- Xstatic struct {
- X long l_count; /* count of strings in table */
- X long l_maxcount; /* maximum strings storable in table */
- X long l_avail; /* characters available in current string */
- X char *l_alloc; /* next available string storage */
- X char **l_table; /* current string table */
- X} literals;
- X
- X
- X/*
- X * Initialize or reinitialize a string header for use.
- X */
- Xvoid
- Xinitstr(hp)
- X register STRINGHEAD *hp; /* structure to be inited */
- X{
- X if (hp->h_list == NULL) {
- X hp->h_list = (char *)malloc(2000);
- X hp->h_avail = 2000;
- X hp->h_used = 0;
- X }
- X hp->h_avail += hp->h_used;
- X hp->h_used = 0;
- X hp->h_count = 0;
- X hp->h_list[0] = '\0';
- X hp->h_list[1] = '\0';
- X}
- X
- X
- X/*
- X * Copy a string to the end of a list of strings, and return the address
- X * of the copied string. Returns NULL if the string could not be copied.
- X * No checks are made to see if the string is already in the list.
- X * The string cannot be null or have imbedded nulls.
- X */
- Xchar *
- Xaddstr(hp, str)
- X register STRINGHEAD *hp; /* header of string storage */
- X char *str; /* string to be added */
- X{
- X char *retstr; /* returned string pointer */
- X char *list; /* string list */
- X long newsize; /* new size of string list */
- X long len; /* length of current string */
- X
- X if ((str == NULL) || (*str == '\0'))
- X return NULL;
- X len = strlen(str) + 1;
- X if (hp->h_avail <= len) {
- X newsize = len + 2000 + hp->h_used + hp->h_avail;
- X list = (char *)realloc(hp->h_list, newsize);
- X if (list == NULL)
- X return NULL;
- X hp->h_list = list;
- X hp->h_avail = newsize - hp->h_used;
- X }
- X retstr = hp->h_list + hp->h_used;
- X hp->h_used += len;
- X hp->h_avail -= len;
- X hp->h_count++;
- X strcpy(retstr, str);
- X retstr[len] = '\0';
- X return retstr;
- X}
- X
- X
- X/*
- X * Return a null-terminated string which consists of a single character.
- X * The table is initialized on the first call.
- X */
- Xchar *
- Xcharstr(ch)
- X{
- X char *cp;
- X int i;
- X
- X if (chartable == NULL) {
- X cp = (char *)malloc(512);
- X if (cp == NULL)
- X math_error("Cannot allocate character table");
- X for (i = 0; i < 256; i++) {
- X *cp++ = (char)i;
- X *cp++ = '\0';
- X }
- X chartable = cp - 512;
- X }
- X return &chartable[(ch & 0xff) * 2];
- X}
- X
- X
- X/*
- X * Find a string with the specified name and return its number in the
- X * string list. The first string is numbered zero. Minus one is returned
- X * if the string is not found.
- X */
- Xlong
- Xfindstr(hp, str)
- X STRINGHEAD *hp; /* header of string storage */
- X register char *str; /* string to be added */
- X{
- X register char *test; /* string being tested */
- X long len; /* length of string being found */
- X long testlen; /* length of test string */
- X long index; /* index of string */
- X
- X if ((hp->h_count <= 0) || (str == NULL))
- X return -1;
- X len = strlen(str);
- X test = hp->h_list;
- X index = 0;
- X while (*test) {
- X testlen = strlen(test);
- X if ((testlen == len) && (*test == *str) && (strcmp(test, str) == 0))
- X return index;
- X test += (testlen + 1);
- X index++;
- X }
- X return -1;
- X}
- X
- X
- X/*
- X * Return the name of a string with the given index.
- X * If the index is illegal, a pointer to an empty string is returned.
- X */
- Xchar *
- Xnamestr(hp, n)
- X STRINGHEAD *hp; /* header of string storage */
- X long n;
- X{
- X register char *str; /* current string */
- X
- X if ((unsigned long)n >= hp->h_count)
- X return "";
- X str = hp->h_list;
- X while (*str) {
- X if (--n < 0)
- X return str;
- X str += (strlen(str) + 1);
- X }
- X return "";
- X}
- X
- X
- X/*
- X * Useful routine to return the index of one string within another one
- X * which has the format: "str1\0str2\0str3\0...strn\0\0". Index starts
- X * at one for the first string. Returns zero if the string being checked
- X * is not contained in the formatted string.
- X */
- Xlong
- Xstringindex(format, test)
- X register char *format; /* string formatted into substrings */
- X char *test; /* string to be found in formatted string */
- X{
- X long index; /* found index */
- X long len; /* length of current piece of string */
- X long testlen; /* length of test string */
- SHAR_EOF
- echo "End of part 9"
- echo "File calc2.9.0/string.c is continued in part 10"
- echo "10" > s2_seq_.tmp
- exit 0
-