ftp.nice.ch/pub/next/developer/languages/ada/Adaed.1.11.s.tar.gz#/Adaed-1.11.0a/arith.c

This is arith.c in view mode; [Download] [Up]

/*
 * Copyright (C) 1985-1992  New York University
 * 
 * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
 * warranty (none) and distribution info and also the GNU General Public
 * License for more details.

 */

/* Avoid problems with library routines on PC that require pointer
 * to double instead of double (this is violation of ANSI specs).
 * for now do not compile these modules
 */

/* 
 * 11-oct-85	shields
 * fix so can handle most negative integer properly. The changes
 * are more in the nature of a patch than a solution. The proper
 * way is NOT to convert negative values to positive form before
 * processing; instead, positive values should be converted to
 * negative and conversions done on negative values. However, this
 * can be put off until later.
 *
 * 5-jun-85	shields
 * add rat_tol and int_tol which are like rat_toi and int_toi, resp.,
 * except that they return long results. These are needed to support
 * fixed-point in generator. 
 *
 * 1-aug-85	shields
 * add calls to int_free() to free intermediate values known to be dead.
 * add some copies where needed in building new rational values.
 */

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include "config.h"
#include "miscprots.h"

typedef struct Rational_s {
	int	   *rnum;		/* numerator */
	int	   *rden;		/* denominator */
}			    Rational_s;
typedef Rational_s * Rational;

#include "arithprots.h"

static int *int_frl(long);
static int *int_ptn(int);
static int *subu_int(int *, int *);
static void int_div(int *, int *, int **, int **);
static int *int__addu(int *, int *);
static int *int__norm(int *);
static int *int_new(int);
static void int_free(int *);
static void rat_free(Rational);
static double pow2(int);

/* Some of the procedures want to signal overflow by returning the
 * string 'OVERFLOW'. In C we do this by setting global arith_overflow
 * to non-zero if overflow occurs, zero otherwise
 */
int arith_overflow = 0;


int	ADA_MIN_INTEGER;
int	ADA_MAX_INTEGER;
int    *ADA_MAX_INTEGER_MP;
int    *ADA_MIN_INTEGER_MP;
long	ADA_MIN_FIXED, ADA_MAX_FIXED;
int	*ADA_MIN_FIXED_MP, *ADA_MAX_FIXED_MP;
/* _LONG form is form that can be held in C (long) */
#ifdef MAX_INTEGER_LONG
long	MIN_INTEGER_LONG;
int    *MAX_INTEGER_LONG_MP;
int    *MIN_INTEGER_LONG_MP;
#endif

#define ABS(x) ((x)<0 ? -(x) : (x))
#define SIGN(x) ((x)<0 ? -1 : (x) == 0 ? 0 : 1)


/*
 * M U L T I P L E     P R E C I S I O N     I N T E G E R
 *
 *	   A R I T H M E T I C	   P A C K A G E
 *
 *		     Robert B. K. Dewar
 *		      June 16th, 1980
 *
 * This package of routines implements multiple precision integer
 * arithmetic using what are called the "classical algorithms" in
 * Knuth "Art of Programming", Volume 2, Section 4.3.1. The style
 * of the algorithms follows Knuth fairly closely, and section
 * 4.3.1 can be consulted for further theoretical details.
 *
 * Multiple precision integers are represented as tuples of small
 * integers in the range 0 to BAS - 1, where BAS is a power of 10
 *(actually 10 ** DIGS) which is the base used to represent the
 * long integers. Essentially the successive elements of the tuple
 * are the digits of the representation in base BAS. All integers
 * are normalized so that the first digit is non-zero, except in
 * the case of zero itself. The sign is carried with the first
 * digit value, all remaining digits are always positive.
 *
 * Some examples of the representation, assuming DIGS = 4 and
 * BAS = 10000(note that the choice of BAS as a power of 10
 * is for convenience of the conversion routines, and is not
 * required for correct operation of the arithmetic algorithms).

 *     -123456789     [-1 , 2345 , 6789]
 *		0     [0]
 *	123456789     [1 , 2345, 6789]

 * The constants BAS and DIGS must be defined as global constants
 * in a program using these routines. It is assumed that the value
 * BAS * BAS - 1 can be represented as a SETL integer value.

 * The following routines are provided:

 *	int_abs		integer absolute value
 *	int_add		integer addition
 *	int_div		integer division
 *	int_eql		integer equal to
 *	int_exp		raise multiple integer to multiple integer power
 *	int_fri		convert multiple precision integer from integer
 *	int_frs		convert multiple precision integer from string
 *	int_geq		integer greater than or equal to
 *	int_gtr		integer greater than
 *	int_len		number of digits in multiple precision integer
 *	int_leq		integer less than or equal to
 *	int_lss		integer less than
 *	int_mod		integer modulus
 *	int_mul		integer multiplication
 *	int_neq		integer not equal to
 *	int_ptn		integer power of ten
 *	int_quo		integer quotient
 *	int_rem		integer remainder
 *	int_sub		integer subtraction
 *	int_toi		convert integer to C integer
 *	int_tos		integer to string
 *	int_umin	integer unary minus
 */

/* Internal procedures have names starting with int__ */

int    *int_abs(int *u)												/*;int_abs*/
{
	/* Absolute value of multiple precision integer */
	int *pu;

	pu = int_copy(u);
	if (pu[1] < 0)
		pu[1] = -pu[1];
	return pu;
}

int    *int_add(int *u, int *v)										/*;int_add*/
{
	/* Add signed integers
	 * This procedure implements the familiar algorithm of comparing
	 * the signs, if the signs are the same, then the result is the
	 * sum of the magnitudes with the sign of the operands. If the
	 * signs differ, then the number with the smaller magnitude is
	 * subtracted from the larger magnitude and the result sign is
	 * that of the operand with the larger magnitude.
	 */

	int	   *t;

	if (u[1] >= 0 && v[1] >= 0)
		return (int__addu(u, v));
	else
		if (u[1] < 0 && v[1] < 0) {
			u[1] = -u[1];
			v[1] = -v[1];
			t = int__addu(u, v);
			u[1] = -u[1];
			v[1] = -v[1];
			t[1] = -t[1];
			return t;
		}
		else {
			int	    us, vs;
			if (us = (u[1] < 0)) {
				u[1] = -u[1];
			}
			if (vs = (v[1] < 0)) {
				v[1] = -v[1];
			}
			if (int_gtr(u, v)) {
				t = subu_int(u, v);
				if (vs) v[1] = -v[1];
				if (us) {
					u[1] = -u[1];
					t[1] = -t[1];
				}
				return t;
			}
			else {
				t = subu_int(v, u);
				if (us) u[1] = -u[1];
				if (vs) {
					v[1] = -v[1];
					t[1] = -t[1];
				}
				return t;
			}
		}
}

int    int_eql(int *u, int *v)										/*;int_eql*/
{
	/* Compare multiple precision integers for equality */

	int	    n;

	if (u[0] != v[0])
		return FALSE;

	for (n = u[0]; n > 0; n--)
		if (u[n] != v[n]) return FALSE;
	return TRUE;
}

int    *int_exp(int *u, int *v)										/*;int_exp*/
{
	/* Raise a multiple precision integer to a multiple precision integer
	 * power using a modified version of the Russian Peasant algorithm
	 * for exponentiation.
	 */

	int	    sn;
	int	    u1;
	int	    i;
	int	    carry;
	int	    half;
	int	   *running, *runningp;
	int	   *result, *resultp;

	/* Compute sign of result: positive if v is even, the sign of u if
	 * v is odd.
	 */

	sn =((v[v[0]] % 2) == 1) ? SIGN(u[1]) : 1;
	u1 = u[1];
	if (u[1] < 0)
		u[1] = -u1;
	v = int_copy(v);

	/* Starting the result at 1 and running at u, loop through the binary
	 * digits of v, squaring running each time, and multiplying the result
	 * by the current value of running each time a 1-bit is found.
	 */

	result = int_con(1);
	running = int_copy(u);

	while(int_nez(v)) {
		/* If v is odd then multiply result by running. */

		if (v[v[0]] % 2 == 1) {
			resultp = result; /* save current value */
			result = int_mul(result, running);
			int_free(resultp); /* free dead value */
		}

		/* Square running. */

		runningp = running; /* save current value */
		running = int_mul(running, running);
		int_free(runningp); /* free dead value */

		/* Halve v. */

		carry = 0;
		for (i = 1; i <= v[0]; i++) {
			half = BAS * carry + v[i];
			carry = half % 2;
			v[i] = half / 2;
		}
		v = int__norm(v);
	}

	int_free(running);
	int_free(v);

	if (sn < 1)
		result[1] = -result[1];
	u[1] = u1;
	return result;
}

int    *int_fri(int i)												/*;int_fri*/
{
	/* Convert an integer to a multiple precision integer.
	 *
	 * First check the sign of i.
	 */

	int	    sn = 0;
	int	    n = i;
	int	   *t;
	int	    ti;
	int	    d;

	if (i < 0) {
		/* Special test for most negative as code below won't work
		 * for this single value (on twos-complement machines)
		 */
		if (i == ADA_MIN_INTEGER)
			return int_copy(ADA_MIN_INTEGER_MP);
		sn = -1;
		n = -i;
	}
	/* Determine length of result */
	d = 0;
	while(n) {
		d++;
		n /= BAS;
	}
	/* Now build up t in groups of BAS digits until i is depleted. */

	if (i < 0)
		i = -i;
	if (i > 0) {
		t = int_new(d);
		ti = t[0];
		while(i) {
			t[ti--] = i % BAS;
			i /= BAS;
		}
	}
	else
		t = int_con(0);

	if (sn < 0)
		t[1] = -t[1];

	return t;
}

#ifdef MAX_INTEGER_LONG
/* variant of int_fri needed for PC only */
static int *int_frl(long i)										/*;int_frl*/
{
	/* Convert a long integer to a multiple precision integer.
	 *
	 * First check the sign of i.
	 */

	int	    sn = 0;
	long    n = i;
	int	   *t;
	int	    ti;
	int	    d;

	if (i < 0) {
		/* Special test for most negative as code below won't work
		 * for this single value (on twos-complement machines)
		 */
		sn = -1;
		n = -i;
	}
	/* Determine length of result */
	d = 0;
	while(n) {
		d++;
		n /= BAS;
	}
	/* Now build up t in groups of BAS digits until i is depleted. */

	if (i < 0)
		i = -i;
	if (i > 0) {
		t = int_new(d);
		ti = t[0];
		while(i) {
			t[ti--] = i % BAS;
			i /= BAS;
		}
	}
	else
		t = int_con(0);

	if (sn < 0)
		t[1] = -t[1];

	return t;
}
#else
/* if ints and longs same size, just use int_fri */
static int    *int_frl(long i)										/*;int_frl*/
{
	return int_fri((int)i);
}
#endif

int    *int_frs(char *s)											/*;int_frs*/
{
	/* Convert a string to multiple precision integer format.  The string
	 * s is a non-empty sequence of digits, possibly preceded by a sign
	 *(+ or -).
	 *
	 * Erroneous strings are converted to OM.
	 *
	 * Since the base is a power of ten, the process of conversion
	 * amounts simply to converting groups of DIGS digits.
	 */

	char   *t;
	int	    dg;
	int	   *r, len;
	int	    ri, z, sn;
	int	    n;

	if (*s == '+') {
		sn = 0;
		s++;
	}
	else
		if (*s == '-') {
			sn = -1;
			s++;
		}
		else
			sn = 0;

	/* now determine length */
	t = s;
	dg = 0;
	while(*t) {
		if (!isdigit(*t++))
			return (int *)0;
		dg++;
	}
	if (dg == 0)
		return (int *)0;

	z = dg % DIGS;
	r = int_new((dg / DIGS) +(z ? 1 : 0));
	ri = 1;
	len = z ? z : DIGS;

	while(dg > 0) {
		n = 0;
		dg -= len;
		while(len--) {		/* convert next len digits */
			n = n * 10 +(*s++ - '0');
		}
		len = DIGS;
		r[ri++] = n;
	}
	if (sn < 0)
		r[1] = -r[1];
	return int__norm(r);
}

int    int_geq(int *u, int *v)										/*;int_geq*/
{
	/* Compare multiple precision integers: return true if u >= v, false
	 * otherwise.
	 */

	return int_eql(u, v) || int_gtr(u, v);
}

int    int_gtr(int *u, int *v)										/*;int_gtr*/
{
	/* Compare multiple precision integers: return true if u > v, false
	 * otherwise.
	 */

	int	    i, neg;

	/* signs are different                       */

	if (u[1] >= 0 && v[1] < 0) return TRUE;

	if (u[1] < 0 && v[1] >= 0) return FALSE;

	/* Now we have a real compare(signs the same) */

	neg = u[1] < 0;   /* get the sign */

	if (u[0] > v[0]) return (neg ? FALSE : TRUE);

	if (u[0] < v[0]) return (neg ? TRUE : FALSE);

	/* Now the lengths are the same  */

	if(u[1] != v[1]) return (u[1] > v[1]);

	/* Most significant digit is the same */

	for (i = 2; i <= u[0]; i++) {
		if (u[i] != v[i]) {
			return (neg ?(v[i] > u[i]) :(u[i] > v[i]));
		}
	}

	/* Numbers are the same */

	return FALSE;
}

/* Not used */
int    int_len(int *u)												/*;int_len*/
{
	/* Return the number of digits in a multiple precision integer. */

	int	    n = 1;
	int	    v;

	v = u[1];
	if (v < 0)
		v = -v;			/* take absolute value */
	while(v) {
		n++;
		v /= 10;
	}
	return n +(u[0] - 1) * DIGS;
}

/* Not used */
int int_leq(int *u, int *v)											/*;int_leq*/
{
	/* Compare multiple precision integers: return true if u <= v, false
	 * otherwise.
	 */

	return ! int_gtr(u, v);
}

int    int_lss(int *u, int *v)										/*;int_lss*/
{
	/* Compare multiple precision integers: return true if u < v, false
	 * otherwise.
	 */

	return ! int_geq(u, v);
}

int    *int_mod(int *u, int *v)										/*;int_mod*/
{
	/* Find u mod v where the mod operation is defined as:
	 *
	 *	u mod v = u - v * N	such that sign(u mod v) = sign v
	 *				      and  abs(u mod v) < abs v
	 */

	int	   *r, *s;

	r = int_rem(u, v);

	if (r == (int *)0 || r[1] == 0 ||(SIGN(u[1]) == SIGN(v[1])))
		return r;
	else {
		s = int_add(r, v);
		int_free(r);
		return s;
	}
}

int    *int_mul(int *u, int *v)		/*;int_mul*/
{
	/* Multiply signed integers, cf Knuth 4.3.1 Algorithm M
	 *
	 * Multiplication is similar to, but not identical with, the
	 * usual pencil and paper algorithm. The main difference is
	 * that the sum is accumulated as we go along, rather than
	 * forming all the partial sums and adding them up at the end.
	 *
	 * First we acquire the sign of the result, and set each number
	 * to its absolute value, thus the multiplication proper always
	 * works with non-negative integers.
	 */

	int	    sn;
	int	    u1;
	int	    v1;
	int	   *w;
	int	    i, j;
	int	    k;
	int	    t;

	sn = u[1] * v[1];
	u1 = u[1];
	v1 = v[1];
	if (u[1] < 0)
		u[1] = -u1;
	if (v[1] < 0)
		v[1] = -v1;
	/* Initialize result to all zeroes(actually it is only absolutely
	 * necessary to initialize the last #v digits of w to zero).
	 */

	w = int_new(u[0] + v[0]);

	/* Outer loop, through digits of multiplier */

	for (j = v[0]; j > 0; j--) {
		/* The inner loop, through the digits of the multiplicand, is
		 * similar to the inner loop of the addition, except that the
		 * product is added in, and the carry, k, can exceed 1.
		 */

		k = 0;
		for (i = u[0]; i > 0; i--) {
			t = u[i] * v[j] + w[i + j] + k;
			w[i + j] = t % BAS;
			k = t / BAS;
		}

		/* The final step in the inner loop is to store the final
		 * carry in the next position in the result.
		 */

		w[j] = k;
	}

	/* The result must be normalized(there could be one leading zero),
	 * and then the result sign attached to the returned value.
	 */

	w = int__norm(w);
	/* Restore arguments to entry value */
	u[1] = u1;
	v[1] = v1;
	if (sn < 0)
		w[1] = -w[1];
	return w;
}

/* Not used */
int    int_neq(int *u, int *v)										/*;int_neq*/
{
	/* Compare multiple precision integers for inequality */

	return ! int_eql(u, v);
}

static int    *int_ptn(int n)										/*;int_ptn*/
{
	/* Return the result 10**n as a multiple precision
	 * integer, where n is a non-negative simple integer.
	 */

	int	    d1;
	int	   *p;
	int	    i;

	d1 = 1;
	for (i = 1; i <= (n % DIGS); i++)
		d1 *= 10;
	p = int_new(1 +(n / DIGS));
	p[1] = d1;
	return p;
}

int    *int_quo(int *u, int *v)										/*;int_quo*/
{
	/* Obtain quotient of dividing u by v */

	int	   *q, *r;

	if (int_eqz(v))
		return (int *)0;
	int_div(u, v, &q, &r);
	if(r != (int *)0) int_free(r); /* remainder not needed, free it */
	return q;
}

int    *int_rem(int *u, int *v)										/*;int_rem*/
{
	/* Obtain remainder from dividing u by v, where u rem v is defined as:
	 *
	 *	u rem v = u -(u/v) * v	   such that sign(u rem v) = sign u
	 *					  and  abs(u rem v) < abs v
	 */

	int	   *q, *r;

	if (int_eqz(v))
		return (int *)0;
	int_div(u, v, &q, &r);
	if (q != (int *) 0) int_free(q); /* quotient not needed, free it */
	return r;
}

int    *int_sub(int *u, int *v)										/*;int_sub*/
{
	/* Subtract signed integers
	 *
	 * There is no point in duplicating the int_add code, so we
	 * simply negate the right argument and call the add routine!
	 */

	int *w;

	v[1] = -v[1];
	w = int_add(u, v);
	v[1] = -v[1];
	return w;
}

int    int_toi(int *t)												/*;int_toi*/
{
	/* Convert a multiple precision integer to a SETL integer, if possible.
	 * Otherwise, return 'OVERFLOW'.
	 *
	 * First check if it overflows.
	 */

	int	    sgn;

	int	    x;
	int	    i;

	arith_overflow = 0;		/* reset overflow flag */
	sgn = SIGN(t[1]);

	if (sgn == 0)
		return 0;
	if (sgn > 0)
		t[1] = -t[1];

	/* the value of t must be in the interval */
	if (int_lss(t, ADA_MIN_INTEGER_MP)
	  || int_gtr(t, ADA_MAX_INTEGER_MP)) {
		if (sgn > 0)
			t[1] = -t[1];	/* restore first component */
		arith_overflow = 1;
		return 0;
	}

	x = t[1]; /* set first part of result (must do here since negative) */
	for (i = 2; i <= t[0]; i++)
		x = BAS * x - t[i];

	if (sgn > 0) {
		t[1] = -t[1];		/* restore sign if negative */
		x = -x;			/* and give result proper value */
	}

	return x;
}

#ifdef MAX_INTEGER_LONG
long int_tol(int *t)											/*;int_tol*/
{
	/* Convert a multiple precision integer to a long integer, if possible.
	 * Otherwise, return 'OVERFLOW'.
	 *
	 * First check if it overflows.
	 */

	int	    sgn;
	long	    x;
	long    res;
	int	    i;

	arith_overflow = 0;		/* reset overflow flag */
	sgn = SIGN(t[1]);

	if (sgn == 0)
		return (long)0;
	if (sgn < 0) {
#ifdef MAX_INTEGER_LONG
		if (int_eql(t, MIN_INTEGER_LONG_MP)) 
			return MIN_INTEGER_LONG;
#else
		if (int_eql(t, ADA_MIN_INTEGER_MP))
			return ADA_MIN_INTEGER;
#endif

		/* since not most negative, can change sign */
		t[1] = -t[1];
	}

#ifdef MAX_INTEGER_LONG
	if (int_gtr(t, MAX_INTEGER_LONG_MP)) {
		arith_overflow = 1;
		return (long) 0;
	}
#else
	if (int_gtr(t, ADA_MAX_INTEGER_MP)) {
		arith_overflow = 1;
		return (long) 0;
	}
#endif

	x = 0;
	for (i = 1; i <= t[0]; i++)
		x = BAS * x + t[i];

	if (sgn < 0)
		t[1] = -t[1];		/* restore sign if negative */

	return (sgn * x);
}
#else
/* if longs and ints are same size, no need for separate procedure */
long int_tol(int *t)											/*;int_tol*/
{
	return (long) int_toi(t);
}
#endif

char   *int_tos(int *u)												/*;int_tos*/
{
	/* Convert a multiple precision integer to a string.
	 * The string is a non-empty digit sequence with a possible leading
	 * minus sign(but a plus sign is never generated).
	 *
	 * As in int_frs, the fact that the base is a power of ten means
	 * that the conversion is simply a matter of converting successive
	 * digits to decimal strings of length DIGS.
	 */

	char   *s, *t;
	int	    i, n;
	if (u == (int *)0) chaos("int_tos: arg null *");

	n = u[0] * DIGS;
	if (u[1] < 0)
		n += 1;			/* if need minus sign */
	s = t = emalloct((unsigned) n + 1, "int-to-s");
	sprintf(s, "%d", u[1]);
	for (i = 2; i <= u[0]; i++) {
		while(*++s);		/* move to end of converted string */
		sprintf(s, "%0*d", DIGS, u[i]);
	}

	return t;
}

int    *int_umin(int *u)										/*;int_umin*/
{
	/* Unary minus on multiple precision integer. */

	u = int_copy(u);
	u[1] = -u[1];
	return u;
}

static int    *subu_int(int *u, int *v)								/*subu_int*/
{
	/* Subtract unsigned integers, u >= v, cf Knuth 4.3.1 Algorithm S
	 *
	 *(note that we know as an entry condition that #u >= #v).
	 */

	int	    ui, vi;
	int	   *w;
	int	    k;			/* borrow */

	w = int_new(u[0]);
	ui = u[0];
	vi = v[0];

	/* The subtraction is similar to the addition, except that k now
	 * represents the borrow condition and has values 0 or -1.
	 */

	k = 0;
	while(vi) {
		w[ui] = u[ui] - v[vi--] + k;
		if (w[ui] < 0) {
			w[ui] += BAS;
			k = -1;
		}
		else
			k = 0;
		ui--;
	}

	/* Loop over remaining digits(if any) of u */

	while(ui) {
		w[ui] = u[ui] + k;
		if (w[ui] < 0) {
			w[ui] += BAS;
			k = -1;
		}
		else
			k = 0;
		ui--;
	}

	/* We cannot have a final borrow(since the entry condition
	 * required that u >= v). However, we must normalize the
	 * result since it is possible for leading zeroes to appear.
	 */

	w = int__norm(w);
	return w;
}

static void int_div(int *u, int *v, int **qa, int **ra)				/*;int_div*/
{
	/* Obtain quotient and remainder of signed integers,
	 * cf Knuth 4.3.1 Algorithm D
	 * Result is returned as a tuple [quotient, remainder].
	 *
	 * This is by far the most difficult of the four basic operations.
	 * This is because the paper and pencil algorithm involves certain
	 * amounts of guess work which cannot be programmed directly. The
	 * approach(which is analyzed in detail in Knuth) is to reduce
	 * the guess work by computing a rather good guess at each digit
	 * of the result, and then correcting if the guess is wrong.
	 *
	 * If the divisor is zero, return om.
	 */

	int	    i, j, k, du, v1, p, c, d;
	int	    rr, rs;
	int	   *r, *q;
	int	   *t, *tt;
	int	    ti, n, m, qe, qs;

	if (int_eqz(v)) {
		*qa = (int *)0;
		*ra = (int *)0;
		return;
	}

	/* A special case, if u is shorter than v, the result is 0 */

	if (u[0] < v[0]) {
		*qa = int_con(0);
		*ra = int_copy(u);
		return;
	}

	/* Otherwise we initialize as in multiplication by obtaining the
	 * result sign and then working with non-negative integers.
	 */

	u = int_copy(u); /* arguments used destructively, so copy */
	v = int_copy(v);
	qs = u[1] * v[1];
	rs = u[1];
	v1 = v[1];
	if (rs < 0)
		u[1] = -rs;
	if (v1 < 0)
		v[1] = -v1;

	/* The case of a one digit divisor is treated specially. Not only
	 * is this more efficient, but the general algorithm assumes that
	 * the divisor contains at least two digits.
	 */

	if (v[0] == 1) {
		q = int_new(u[0]);

		/* Basically this case is straight-forward. Since we can represent
		 * numbers up to BAS * BAS - 1, we can do the steps of the division
		 * exactly without any need for guess work. The division is then
		 * done left to right(essentially it is the short division case).
		 */
		rr = 0;
		for (j = 1; j <= u[0]; j++) {
			du = rr * BAS + u[j];
			q[j] = du / v[1];
			rr = du % v[1];
		}

		r = int_con(rr);
	}
	/* Here is where we must do the full long division algorithm */

	else {
		n = v[0];
		m = u[0] - v[0];
		q = int_new(m+1);
		t = int_new(u[0] + 1);	/* extend u */
		for (j = 1; j <= u[0]; j++)
			t[j + 1] = u[j];
		int_free(u);
		u = t;

		/* The first step is to multiply both the divisor and dividend
		 * by a scale factor. Obviously such scaling does not affect
		 * the quotient. The purpose of this scaling is to ensure that
		 * the first digit of the divisor is at least BAS / 2. This
		 * condition is required for proper operation of the quotient
		 * estimation algorithm used in the division loop. Note that
		 * we added an extra digit at the front of the dividend above.
		 */

		d = BAS /(v[1] + 1);

		c = 0;
		for (j = u[0]; j > 0; j--) {
			p = u[j] * d + c;
			u[j] = p % BAS;
			c = p / BAS;
		}

		c = 0;
		for (j = v[0]; j > 0; j--) {
			p = v[j] * d + c;
			v[j] = p % BAS;
			c = p / BAS;
		}

		/* This is the major loop, corresponding to long division steps */

		for (j = 1; j <= (m + 1); j++) {
			/* Guess the next quotient digit by doing a division based on the
			 * leading digits. This estimate is never low and at most 2 high.
			 */
			qe =(u[j] != v[1])
			    ?((u[j] * BAS + u[j + 1]) / v[1])
			    :(BAS - 1);

			/* The following loop refines this guess so that it is almost always
			 * correct and is at worst one too high(see Knuth for proofs).
			 */

			while((v[2] * qe) >
			    ((u[j] * BAS + u[j + 1] - qe * v[1]) * BAS + u[j + 2])) {
				qe -= 1;
			}

			/* Now(for the moment accepting the estimate as correct), we
			 * subtract the appropriate multiple of the divisor. This is
			 * similar to the inner loop of the multiplication routine.
			 */
			c = 0;
			for (k = n; k > 0; k--) {
				du = u[j + k] - qe * v[k] + c;
				u[j + k] = du % BAS;
				c = du / BAS;
				if (u[j + k] < 0) {
					u[j + k] += BAS;
					c -= 1;
				}
			}
			u[j] += c;

			/* If the estimate was one off, then u(j) went negative when the
			 * final carry was added above. In this case, we add back the
			 * divisor once, and adjust the quotient digit.
			 */

			if (u[j] < 0) {
				qe -= 1;

				c = 0;
				for (k = n; k > 0; k--) {
					u[j + k] += v[k] + c;
					if (u[j + k] >= BAS) {
						u[j + k] -= BAS;
						c = 1;
					}
					else
						c = 0;
				}

				u[j] += c;
			}

			/* Store the next quotient digit */

			q[j] = qe;
		}

		/* Remainder is in u(m+2..m+n+1) but must be divided by d. */


		/* SETL:      r:=int_quo(u(m+2..m+n+1), [d]); */
		t = int_new(n);
		ti = 1;
		for (i = m + 2; i <= (m + n + 1); i++)
			t[ti++] = u[i];
		r = int_quo(t, tt=int_con(d));
		int_free(t);
		int_free(tt);
	}

	/* All done, except for normalizing the quotient
	 * to remove leading zeroes and supplying the
	 * proper result sign to the returned values.
	 */

	q = int__norm(q);
	if (qs < 0)
		q[1] = -q[1];
	if (rs < 0)
		r[1] = -r[1];
	*qa = q;
	*ra = r;

	int_free(u);
	int_free(v);
}

static int    *int__addu(int *u, int *v)						/*;int__addu*/
{
	/* Add unsigned integers, cf Knuth 4.3.1 Algorithm A
	 *
	 * We first do the addition just to see if final carry, so we
	 * can determine correct length of result. Then we allocate
	 * the result and perform the addition.
	 */

	int	    k = 0;		/* carry */
	int	   *w;
	int	    r;
	int	    ui, vi, wi;

	/* Adjust so u points to longer argument */

	if (v[0] > u[0]) {		/* if second longer */
		w = u;
		u = v;
		v = w;
	}
	ui = u[0];			/* length of first argument */
	vi = v[0];
	while(vi) {
		r = u[ui--] + v[vi--] + k;
		if (r >= BAS)
			k = 1;
		if (r < BAS)
			k = 0;
	}
	while(ui) {
		r = u[ui--] + k;
		if (r >= BAS)
			k = 1;
		if (r < BAS)
			k = 0;
	}
	/* if k nonzero, result needs extra component */
	w = int_new(u[0] + k);
	/* Now perform addition for real */

	/* Now we perform the addition from right to left in the familiar
	 * paper and pencil manner. The variable k is the carry from the
	 * previous column, which has either the value zero or one.
	 */

	ui = u[0];
	vi = v[0];
	wi = w[0];
	k = 0;
	while(vi) {
		w[wi] = u[ui--] + v[vi--] + k;
		if (w[wi] >= BAS) {
			w[wi] -= BAS;
			k = 1;
		}
		else
			k = 0;
		wi--;
	}
	/* Now add in remainder of longer number */
	while(ui) {
		w[wi] += u[ui--] + k;
		if (w[wi] >= BAS) {
			w[wi] -= BAS;
			k = 1;
		}
		else
			k = 0;
		wi--;
	}
	if (k)
		w[1] = 1;		/* if final carry */

	return w;
}

/* Note that int__norm does not alter its argument, but returns
 * pointer to(possibly normalized) multi-precision integer.
 */
static int    *int__norm(int *u)								/*;int__norm*/
{
	/* Remove leading zeroes from calculated value
	 *
	 * The representation used in this package requires that all integer
	 * values be normalized, i.e. the first digit of any stored value
	 * must be non-zero except for the special case of zero itself. The
	 * normalize routine is called to ensure this condition is met.
	 *
	 */

	int	    i, j, *v;

	if (u[0] == 1 || u[1] != 0)
		return (u);

	for (i = 2; i <= u[0]; i++) {
		if (u[i]) {
			v = int_new(u[0] -(i - 1));
			for (j = 1; j <= v[0]; j++) {
				v[j] = u[i++];
			}
			int_free(u);
			return (v);
		}
	}
	/*  Return zero if all components zero */
	return int_con(0);
}

/* Not used */
int	value(char *s)													/*;value*/
{
	/* Convert a numeric string to an integer. */
	return atoi(s);
}

static int    *int_new(int n)										/*;int_new*/
{
	/* Allocate new integer with n components, each initially zero */
	int	   *p;
	int	    i;

	p =(int *) ecalloct((unsigned) n + 1, sizeof(int), "int-new");
	p[0] = n;
	for (i = 1; i <= n; i++)
		p[i] = 0;
	return p;
}

static void int_free(int *n)									/*;int_free*/
{
	efreet((char *) n, "int-free");
}

int    *int_con(int i)												/*;int_con*/
{
	/* Build multi-precision integer from standard (short) integer */
	int	   *p;

	if (i<-BAS || i > BAS) chaos("int_con arg out of range ");

	p = int_new(1);
	p[1] = i;
	return p;
}

int    *int_copy(int *u)										/*;int_copy*/
{
	/* Return copy of multi-precision integer u */
	int	   *p;
	int	    n, i;

	p = int_new(n = u[0]);
	for (i = 1; i <= n; i++)
		p[i] = u[i];

	return p;
}

int	int_eqz(int *u)												/*;int_eqz*/
{
	/*  Compare multi-precision integer with zero */

	int	    i;

	for (i = 1; i <= u[0]; i++)
		if (u[i]) return (FALSE);
	return TRUE;
}

int	int_nez(int *u)													/*;int_nez*/
{
	/* Compare multi-precision integer with zero; true if not zero */
	return ! int_eqz(u);
}

/* end module ada - arith */

#ifdef DEBUG
/* debugging and test procedures */
void int_print(int *u)											/*;int_print*/
{
	/* Dump multi-precision integer to standard output */
	int	    i, n;
	n = u[0];
	if (n <= 0) {
		chaos("ill-formatted arbitrary precision integer - lengt <= 0");
	}
	printf("integer: %d components\n", u[0]);
	printf("%3d %*d\n", 1, DIGS+1, u[1]); /* allow for possible sign */
	for (i = 2; i <= u[0]; i++)
		printf("%3d  %0*d\n", i, DIGS, u[i]);
}
#endif

/*		module ada - arith   */
/*
 * All integers are stored in the multiple precision form used
 * in the package which is included as part of this program,
 * and rationals are stored as a pair [numerator, denominator],
 * with the denominator always positive, and [0] stored as [[0], n].
 * A rational plus or minus infinity may be represnted as
 * [n, [0]] or [-n, [0]] respectively. A rational of the form [[0], [0]]
 * will have an undefined effect if used in an operation.
 */

/* Macros for access to rational numbers: */

#define num(x) x->rnum
#define den(x) x->rden

Rational RAT_TWO;
Rational ADA_MAX_FLOAT;

/*
 * R A T I O N A L     A R I T H M E T I C     P A C K A G E

 *		     Robert B. K. Dewar
 *		      June 18th, 1980

 * This package contains a set of routines for performing
 * rational multiple precision arithmetic.

 *
 * A rational number is represented as a struct with two components, rnum
 * and rden, where num is the numerator, which may be negative, and den is
 * the denominator, which is non-zero and positive. Usually rational
 * numbers are reduced to lowest terms(see procedure rat_red), but none of
 * the routines depend on this assumption. The numerator and denominator
 * are represented as multiple precision integers, using the standard
 * formats for the multiple precision integer package, which must be
 * included as part of the program.
 * The macros num() and den() are used often, for comparison with the
 * original SETL code.
 *
 * The following routines are provided in the package

 *	rat_abs		rational absolute value
 *	rat_add		rational addition
 *	rat_div		rational division
 *	rat_eql		rational equal to
 *	rat_exp		raise rational to multiple precision integer power
 *	rat_fri		convert multiple precision integers to rational
 *	rat_frr		convert real to rational
 *	rat_frs		convert rational from string
 *	rat_geq		rational greater than or equal to
 *	rat_gtr		rational greater than
 *	rat_leq		rational less than or equal to
 *	rat_lss		rational less than
 *	rat_mul		rational multiplication
 *	rat_neq		rational not equal to
 *	rat_rec		rational reciprocal
 *	rat_red		reduce rational to lowest terms
 *	rat_str		convert integral fraction to string fraction
 *	rat_sub		rational subtraction
 *	rat_tor		convert rational to real
 *	rat_toi		convert rational to integer(rounds)
 *	rat_tos		convert rational to string
 *	rat_tup		convert string fraction to integral fraction
 *	rat_umin	rational unary minus
 */

/*
 * The following procedures are introduced in the translation to C:
 *	rat_new		allocate new rational, set components
 *	rat_free	free rational(deallocate space, including
 *			  space used by components
 */

void rat_init()													/*;rat_init*/
{
	/* Initialize rational and multi-precision packages */

	extern  Rational RAT_TWO;
	extern  Rational ADA_MAX_FLOAT;

	RAT_TWO = rat_new(int_con(2), int_con(1));

	/*    ADA_MAX_FLOAT	=
	 *	[[79, 228, 162, 514, 264, 337, 593, 543, 950, 336], [1]],
	 *				$ rational form of MAX_FLOAT
	 *    ADA_MAX_INTEGER_MP= [1, 073, 741, 823],
	 *				$ long form of ADA_MAX_INTEGER
	 */
	/* Some C compilers do not like to see the most negative integer as
	 * a constant, so we initialize ADA_MIN_INTEGER here by assingment
	 * (assuming they can subtract properly!)
	 */
	ADA_MAX_INTEGER = MAX_INTEGER; /* to be sure */
	ADA_MIN_INTEGER = -ADA_MAX_INTEGER;
	ADA_MIN_INTEGER--;
	ADA_MAX_INTEGER_MP = int_fri(ADA_MAX_INTEGER);
	ADA_MIN_INTEGER_MP = int_sub(int_umin(ADA_MAX_INTEGER_MP), int_fri(1));
#ifdef MAX_INTEGER_LONG
	MIN_INTEGER_LONG = - MAX_INTEGER_LONG;
	MIN_INTEGER_LONG--;
	MAX_INTEGER_LONG_MP = int_frs(MAX_INTEGER_LONG_STRING);
	MIN_INTEGER_LONG_MP = int_sub(int_umin(MAX_INTEGER_LONG_MP),
	  int_fri(1));
	ADA_MIN_FIXED = MIN_INTEGER_LONG;
	ADA_MAX_FIXED = MAX_INTEGER_LONG;
	MAX_INTEGER_LONG_MP = int_frs(MAX_INTEGER_LONG_STRING);
	MIN_INTEGER_LONG_MP = int_sub(int_umin(MAX_INTEGER_LONG_MP),
	  int_fri(1));
	ADA_MIN_FIXED_MP = MIN_INTEGER_LONG_MP;
	ADA_MAX_FIXED_MP = MAX_INTEGER_LONG_MP;
#endif
#ifndef MAX_INTEGER_LONG
	ADA_MIN_FIXED = ADA_MIN_INTEGER;
	ADA_MAX_FIXED = ADA_MAX_INTEGER;
	ADA_MIN_FIXED_MP = ADA_MIN_INTEGER_MP;
	ADA_MAX_FIXED_MP = ADA_MAX_INTEGER_MP;
#endif
	ADA_MAX_FLOAT = rat_new(
	  int_frs("79228162514264337593543950336"),
	  int_con(1));
}

Rational rat_new(int *u, int *v)								/*;rat_new*/
{
	Rational r;

	r =(Rational) emalloct(sizeof(Rational_s), "rat-new");
	r -> rnum = u;
	r -> rden = v;
	return r;
}

static void rat_free(Rational r)								/*;rat_free*/
{
	if (r->rnum != (int *)0) efreet((char *) r->rnum, "rat-free-num");
	if (r->rden != (int *)0) efreet((char *) r->rden, "rat-free-den");
	efreet((char *) r, "rat-free-rat");
}

#ifdef DEBUG
void rat_print(Rational r)									/*;rat_print*/
{
	printf("rational \n");
	int_print(r -> rnum);
	int_print(r -> rden);
}
#endif

Rational rat_abs(Rational u)										/*;rat_abs*/
{
	/* Absolute value of rational number */

	return rat_new(int_abs(num(u)), int_copy(den(u)));
}

Rational rat_add(Rational u, Rational v)							/*;rat_add*/
{
	/* Add rational numbers
	 *
	 *   un	    vn	      un * vd  +  vn * ud
	 *   --	 +  --	 =    -------------------
	 *   ud	    vd		    ud * vd
	 */

	int	   *rn, *rm, *tn, *tm;

	tn = int_mul(num(u), den(v));
	tm = int_mul(num(v), den(u));
	rn = int_add(tn, tm);
	rm = int_mul(den(u), den(v));
	int_free(tn); 
	int_free(tm); /* free temporaries */

	return rat_new(rn, rm);
}


Rational rat_div(Rational u, Rational v)							/*;rat_div*/
{
	/*
	 * Divide rational numbers
	 *
	 *    un
	 *    --
	 *    ud
	 *		  un * vd
	 *   ----    =	  -------
	 *		  vn * ud
	 *    vn
	 *    --
	 *    vd
	 *
	 * Test for division by zero
	 */

	int	   *rn, *rm;

	/* Return NULL instead of OM */
	if (int_eqz(num(v))) return ((Rational)0);

	/* Divisor is non-zero */

	else {
		rn = int_mul(num(u), den(v));
		rm = int_mul(num(v), den(u));
		/*   if rm < 0 then
		 *	rn := -rn;
		 *	rm := abs rm;
		 *   end if;
		 */
		if (rm[1] < 0) {
			rn[1] = -rn[1];
			rm[1] = -rm[1];
		}

		return rat_new(rn, rm);
	}
}

int rat_eql(Rational u, Rational v)									/*;rat_eql*/
{
	/* Test rational numbers for equality */
	int	*rm, *rn, res;

	rn = int_mul(num(u), den(v));
	rm = int_mul(num(v), den(u));
	res = int_eql(rn, rm);
	int_free(rn); 
	int_free(rm); /* free temporaries */
	return res;
}

Rational rat_exp(Rational u, int *ea)		/*;rat_exp*/
{
	/* Raise rational number to multiple precision integer power
	 *
	 *  If e >= 0:		   If e < 0:
	 *
	 *    un	un ** e	     un		     1		 ud **(-e)
	 *    -- ** e = -------	     -- ** e = --------------- = ----------
	 *    ud	ud ** e	     ud	      (un/ud) **(-e)	 un **(-e)
	 */

	int	   *e;

	if (int_eqz(num(u)))
		return int_eqz(ea) ? rat_new(int_con(1), int_con(1))
		  : rat_new(int_con(0), int_con(1));

	e = int_copy(ea);		/* preserve value semantics */

	if (e[1] < 0) {
		u = rat_rec(u);
		e[1] = -e[1];
	}

	return rat_new(int_exp(num(u), e), int_exp(den(u), e));
}

Rational rat_fri(int *u, int *v)		/*;rat_fri*/
{
	/* Convert multiple precision integers to a rational number. */

	return rat_new(int_copy(u), int_copy(v));
}

Rational rat_frr(double u)											/*;rat_frr*/
{
	/* Convert a SETL real to a rational number.
	 *
	 * converts a floating number u to a pair of integers [p, y] such that
	 * u = 2.0**p * float y
	 * Here y satisfies 2**(N-1) <= abs y < 2 ** N
	 * where N is the number of mantissa bits.
	 * This essentially separates the fraction and the exponent.
	 */
	/* The present C version is a straightforward translation of the SETL
	 * code. Still unanswered is the question of whether real values will
	 * be represented in C using doubles or floats; for now we assume reals
	 * as floats. A more efficient version using library function 'frexp'
	 * may be possible.
	 */

	int	    sgn;
	float   ub, lb;
	int	    p, y;
	if (u == 0.0)
		return rat_new(int_con(0), int_con(1));

	if (u < 0) {
		u = -u;
		sgn = -1;
	}
	else {
		sgn = 1;
	}
	ub = pow2(ADA_MANTISSA_SIZE);
	lb = pow2(ADA_MANTISSA_SIZE - 1);

	p =(int)(log((double) u) / log((double) 2.0)) - ADA_MANTISSA_SIZE;
	/* estimate the exponent */
	u = u * pow2(-p);
	/* and adjust number */
	while(u >= ub) {
		u /= 2.0;		/* scale down */
		p += 1;
	}
	while(u < lb) {
		u *= 2.0;		/* scale up; */
		p -= 1;
	}
	y = sgn *(int) u;
	return rat_mul(rat_exp(RAT_TWO, int_fri(p)),
	  rat_new(int_fri(y), int_con(1)));
}

/* Not used */
Rational rat_frs(char *s)											/*;rat_frs*/
{
	/* Convert a string representing a decimal fraction to the corresponding
	 * rational number.  The string consists of a digit string, optionally
	 * containing a decimal point and preceded by an optional sign.	 If an
	 * erroneous string is passed as an argument, then OM is returned.
	 *
	 * First step is to find number of digits after decimal point
	 */

	int	    dp, n, frac;
	int	   *i;
	char   *t;

	n = strlen(s);

	t = strrchr(s, '.');
	frac =(t == (char *)0) ? 0 :(t - s + 1);
	/* find position of decimal point */
	dp = 0;
	if (frac != 0) {
		dp = n - frac;
		t = emalloct((unsigned) n, "rat-frs");
		*t = '\0';		/* mark end of(initially) null string */
		if (frac > 1)
			strncat(t, s, frac - 1);
		strncat(t, s + frac, (n - frac));
	}
	else
		t = s;
	/* Then number is converted as integer, and result is obtained
	 * by supplying the appropriate power of ten as the denominator.
	 */

	i = int_frs(t);

#ifdef XDEFER
	/* defer this while putting salloc in place DS (2-22-86) */
	if (frac)
		efreet(t, "rat-frs");		/* return t if allocated here */
#endif

	if (i == (int *)0)
		return (Rational)0;
	else
		return rat_red(i, int_ptn(dp));
}

int rat_geq(Rational u, Rational v)									/*;rat_geq*/
{
	/* Compare rational numbers: return true if u >= v, false otherwise. */

	return ! rat_lss(u, v);
}

int rat_gtr(Rational u, Rational v)									/*;rat_gtr*/
{
	/* Compare rational numbers: return true if u > v, false otherwise. */

	return (rat_eql(u, v) ? 0 : rat_lss(v, u));
}

int rat_leq(Rational u, Rational v)									/*;rat_leq*/
{
	/* Compare rational numbers: return true if u <= v, false otherwise. */

	return (rat_eql(u, v) ? 1 : rat_lss(u, v));
}

int rat_lss(Rational u, Rational v)			/*;rat_lss*/
{
	/* Compare rational numbers: return true if u < v, false otherwise.
	 *
	 *   un	    vn
	 *   -- <  --	iff   un * vd  <  vn * ud
	 *   ud	    vd
	 */
	int	*rn, *rd, res;
	rn = int_mul(num(u), den(v));
	rd = int_mul(num(v), den(u));
	res = int_lss(rn, rd);
	int_free(rn); 
	int_free(rd);
	return res;
}

Rational rat_mul(Rational u, Rational v)							/*;rat_mul*/
{
	/*
	 * Multiply rational numbers
	 *
	 *   un	    vn	      un * vn
	 *   --	 *  --	 =    -------
	 *   ud	    vd	      ud * vd
	 */

	int	   *rn, *rm;

	rn = int_mul(num(u), num(v));
	rm = int_mul(den(u), den(v));

	return rat_red(rn, rm);
}

int rat_neq(Rational u, Rational v)									/*;rat_neq*/
{
	/* Test rational numbers for inequality */

	return ! rat_eql(u, v);
}

Rational rat_rec(Rational u)										/*;rat_rec*/
{
	/* Find reciprocal of rational number(number should not be zero). */

	int	   *un, *dn;

	un = int_copy(den(u));
	dn = int_copy(num(u));
	if (dn[1] < 0) {
		un[1] = -un[1];
		dn[1] = -dn[1];
	}
	return rat_new(un, dn);
}

Rational rat_red(int *un, int *ud)									/*;rat_red*/
{
	/* Form rational reduced to lowest terms
	 *
	 * This procedure is given as arguments the numerator and denominator
	 * of a rational value(as multiple precision integers). It returns
	 * the rational formed by reducing these values to lowest terms.
	 *
	 * First a special case: zero is reduced to [[0], [1]] .
	 */

	int	   *i, *j, *t, *gcd, usign, dsign, rsign;

	if (int_eqz(un)) {
		return rat_new(int_con(0), int_con(1));

		/* Another special case: plus or minus infinity is reduced to [[1], [0]]
		 * or [[-1], [0]] .
		 */
	}
	else {
		if (int_eqz(ud)) {
			return rat_new(int_con((un[1] < 0 ? -1 :((un)[1] > 0 ? 1 : 0))),
			  int_con(0));
		}
		/* Else we must compute GCD, using Euclid's algorithm. */

		else {
			usign = SIGN(un[1]); 
			dsign = SIGN(ud[1]);
			rsign = usign == dsign ? 1 : -1;
			i = int_copy(un);
			i[1] = i[1] >= 0 ? i[1] : -i[1];
			j = int_copy(ud);
			j[1] = j[1] >= 0 ? j[1] : -j[1];
			if (int_gtr(j, i)) {
				t = i;
				i = j;
				j = t;
			}
			/* Steps of Euclid's algorithm, at each step, i is greater than
			 * or equal to j, i is replaced by j and j is replaced by the
			 * remainder of dividing i by j. The algorithm terminates when
			 * j is zero, with i being the greatest common divisor.
			 */

			while(int_nez(j)) {
				t = j;
				j = int_rem(i, j);
				i = t;
				/* [i, j] := [j, int_rem(i, j)]; */
			}

			gcd = i;

			/* Now reduce the original to lowest terms using the computed GCD */

			i = int_quo(un, gcd);
			j = int_quo(ud, gcd);
			/* adjust signs if needed */
			if (i[1] < 0) i[1] = -i[1];
			if (j[1] < 0) j[1] = -j[1];
			if (rsign < 0) i[1] = -i[1];
			return  rat_new(i, j);

		}
	}
}

#ifdef TBSN
char **rat_str(int **q)												/*;rat_str*/
{
	/* Convert tuple of multiple precision integers to tuple of
	 * strings.
	 * We interpret the argument q as a pointer to an array of pointers
	 * to multi-precision integers.
	 */

	char *emalloct();
	char *p;

	p = ecalloct(2, sizeof(char *), "rat-str");
	p[0] = int_tos(*q[0]);
	p[1] = int_tos(*q[1]);
	return &p;
}
#endif

Rational rat_sub(Rational u, Rational v)							/*;rat_sub*/
{
	/* Subtract rational numbers
	 *
	 *   un	    vn	      un * vd  -  vn * ud
	 *   --	 -  --	 =    -------------------
	 *   ud	    vd		    ud * vd
	 */

	int	   *rn, *rm, *tn, *tm;

	tn = int_mul(num(u), den(v));
	tm = int_mul(num(v), den(u));
	rn = int_sub(tn, tm);
	int_free(tn); 
	int_free(tm);
	rm = int_mul(den(u), den(v));
	return rat_new(rn, rm);
}

double rat_tor (Rational u, int n)									/*;rat_tor*/
{
	/* TBSL: need to review and test this code		ds 11 sep 84 */
	double	real1;
	int	sgn, numpow, denpow;
	int	*nu, *du;
	int	*ub, *lb, p, *lbnd;
	int	*iquo;
	long	ntmp;
	double	log_bas, rpow, res;
	/* Convert a multiple precision real to a SETL real, if possible.
	 * Make copy and work with positives
	 */
	u = rat_red(num(u), den(u));
	arith_overflow = 0;
	nu = num(u);
	sgn   = SIGN(nu[1]);
	nu[1] = ABS(nu[1]);

	/* Check for 0 */

	if (sgn == 0 ) { 
		rat_free(u);
		return 0.0;
	}

	/* Check for overflow */

	if (rat_gtr(u, ADA_MAX_FLOAT)) {
		arith_overflow = 1;
		return 0.0;
	}

	/* To find an accurate floating representation of a rational number,
	 * we normalize it so that
	 *
	 *		2 ** (N - 1) <= (num/den) < 2 ** N
	 *
	 * where N is the size of the mantissa.
	 * We can then perform a long division, and know that the mantissa is
	 * accurate to 2 ** (-N) i.e. to the last bit.
	 */
	real1 = BAS;
	log_bas = log(real1) / log(2.0);
	ub = int_frl((long) pow2(ADA_MANTISSA_SIZE));
	lb = int_frl((long) pow2(ADA_MANTISSA_SIZE - 1));

	nu = num(u);
	du = den(u);
	numpow = (int)((double)((nu[0]-1)) * log_bas + log((double)nu[1])/log(2.0));
	denpow = (int)((double)((du[0]-1)) * log_bas + log((double)du[1])/log(2.0));

	p = numpow - denpow - ADA_MANTISSA_SIZE;
	if (p < 0 ) {				/* -p > 0 */
		nu = int_mul(nu, int_exp(int_fri(2), int_fri(-p)));
	}
	else {					/*  p >= 0  */
		du = int_mul(du, int_exp(int_fri(2), int_fri(p)));
	}

	while (int_geq(nu, int_mul(ub, du))) {
		du = int_add(du, du);
		p++;
	}
	lbnd = int_mul(lb, du);
	while (int_lss(nu, lbnd)) {
		nu = int_add(nu, nu);
		p--;
	}
	iquo = int_quo(nu, du);
	ntmp = int_tol(iquo);
	real1 = sgn * ntmp;
	rpow = pow2(p);
	res = real1 * rpow;
	return res;
}

int	rat_toi(Rational u)												/*;rat_toi*/
{
	/* Convert the rational number u to a SETL integer.  The number
	 * u is rounded by adding rational 1/2 or -1/2.	 The int_quo
	 * procedure is used to obtain the result of dividing the
	 * numerator by the denominator.  The resuling extended integer is
	 * then converted to a SETL integer using int_toi.
	 */

	int	    t, s;
	Rational r;

	t = num(u)[1];
	s = t == 0 ? 0 : t > 0 ? 1 : -1;/* get sign of u */
	/* s := sign num(u)(1);		$ get sign of u */
	/*	add or subtract 1/2(or 0) */
	r = rat_add(u, rat_new(int_con(s), int_con(2)));
	return int_toi(int_quo(num(r), den(r)));
	/* get quotient and convert it */
}

long rat_tol(Rational u)										/*;rat_tol*/
{
	/* Convert the rational number u to a (long)integer.  The number
	 * u is rounded by adding rational 1/2 or -1/2.	 The int_quo
	 * procedure is used to obtain the result of dividing the
	 * numerator by the denominator.  The resuling extended integer is
	 * then converted to a SETL integer using int_toi.
	 */

	int	    t, s;
	Rational r;

	t = num(u)[1];
	s = t == 0 ? 0 : t > 0 ? 1 : -1;/* get sign of u */
	/* s := sign num(u)(1);		$ get sign of u */
	/*	add or subtract 1/2(or 0) */
	r = rat_add(u, rat_new(int_con(s), int_con(2)));
	return int_tol(int_quo(num(r), den(r)));
	/* get quotient and convert it */
}

#ifdef TBSN
	proc rat_tos (u, n);		/*;rat_tos*/
	
	/*
	 * Convert a rational number u to a decimal
	 * string with n places after the decimal point. The result
	 * is correctly rounded and always has the specified number
	 * of digits after the decimal place (even if they are zero)
	 *
	 * First acquire the sign (and then work with positive numbers)
	 */
	
	int *q, *r;
	
	sn :
	= '';
	if num(u)(1) < 0 then
	num(u)(1) :
	= abs num(u)(1);
	sn	      :
	= '-';
	end if;
	
	/*
	 * Form result by multiplying by power of ten corresponding
	 * to number of decimal places and then doing division.
	 */
	
	un :
	= int_mul (num(u), int_ptn (n));
	ud :
	= den(u);
	int_div(un, ud, &q, &r);
	if int_gtr (int_mul (r, [2]), ud) then
	q:
	=int_add(q, [1]);
	end if;
	
	/*
	 * Return result by converting this integer to a string and
	 * then supplying the decimal point at the appropriate position.
	 */
	
	q :
	= int_tos (q);
	if #q <= n then
	q :
	= (n + 1 - #q) * '0' + q;
	end if;
	
	return sn + q(1..#q-n) + '.' + q(#q-n+1..);
	
	end proc rat_tos;
#endif

#ifdef TBSN
Rational *rat_tup(char **q)											/*;rat_tup*/
{
	/* Convert tuple of strings to tuple of multiple precision integers.
	 * We interpret tuple of strings as pointer to array of pointers to
	 * strings.
	 */

	char *ecalloct();
	Rational *p;

	p = ecalloct(2, sizeof(Rational ), "rat-tup");

	p[0] = int_frs(*q[0]);
	p[1] = int_frs(*q[1]);
	return &p;
}
#endif

Rational rat_umin(Rational u)									/*;rat_umin*/
{
	/* Rational unary minus */

	return rat_new(int_umin(num(u)), int_copy(den(u)));
}

static double pow2(int p)							                 /*;pow2*/
{
	double running, result;

    result = 1.0;

    if (p < 0) {
		running = 0.5;
	    p = -p;
	}
	else {
		running = 2.0;
	}

	while(p != 0) {

		/* If p is odd then multiply result by running. */

		if (p % 2 == 1)
			result = result * running;

		/* Square running. */

		running = running * running;

	    p /= 2;
	}

	return result;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.