This is rational.c in view mode; [Download] [Up]
/****************************************************************************
**
*A rational.c GAP source Martin Schoenert
**
*A @(#)$Id: rational.c,v 3.3 1991/04/30 16:12:38 martin Rel $
**
*Y Copyright 1990-1992, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
**
** This file contains the functions for the artithmetic of rationals.
**
** Rationals are the union of integers and fractions. A fraction is a
** quotient of two integers where the denominator does not evenly divide the
** numerator. If in the description of a function we use the term rational
** this implies that the function is also capable of handling integers,
** though its function would usually be performed by a routine in the
** integer package. We will use the term fraction to stress the fact that
** something must not be an integer.
**
** A fraction is represented as a pair of two integers. The first is the
** numerator and the second is the denominator. This representation is
** always reduced, i.e., numerator and denominator are relative prime. The
** denominator is always positive and greater than 1. If it were 1 the
** fraction would be an integer and would be represented as integer. Since
** the denominator is always positive the numerator carries the sign of the
** fraction.
**
** It is very easy to see that for every fraction there is one unique
** reduced representation. Because of this comparisons of fractions are
** quite easy, we just compare numerator and denominator. Also numerator
** and denominator are as small as possible, reducing the effort to compute
** with them. Of course computing the reduced representation comes at a
** cost. After every arithmetic operation we have to compute the greatest
** common divisor of numerator and denominator, and divide them by the gcd.
**
** Effort has been made to improve efficiency by avoiding unneccessary gcd
** computations. Also if possible this package will compute two gcds of
** smaller integers instead of one gcd of larger integers.
**
** However no effort has been made to write special code for the case that
** some of the integers are small integers (i.e., less than 2^28). This
** would reduce the overhead introduced by the calls to the functions like
** 'SumInt', 'ProdInt' or 'GcdInt'.
**
*H $Log: rational.c,v $
*H Revision 3.3 1991/04/30 16:12:38 martin
*H initial revision under RCS
*H
*H Revision 3.2 1990/11/23 12:00:00 martin
*H fixed 'IsRat' for large negative numbers
*H
*H Revision 3.1 1990/10/02 12:00:00 martin
*H fixed 'PowRat' for negative exponents
*H
*H Revision 3.0 1990/09/09 12:00:00 martin
*H fixed 'LtRat', which always returned 'true'
*H
*/
#include "system.h" /* system dependent functions */
#include "gasman.h" /* dynamic storage management */
#include "scanner.h" /* reading of tokens and printing */
#include "eval.h" /* evaluator main dispatcher */
#include "integer.h" /* arbitrary size integers */
#include "rational.h" /* declaration part of the package */
/****************************************************************************
**
*F EvRat( <hdRat> ) . . . . . . . . . . . . . . . . . . evaluate a rational
**
** 'EvRat' returns the value of the rational <hdRat>. Because rationals are
** constants and thus selfevaluating this just returns <hdRat>.
*/
TypHandle EvRat ( hdRat )
TypHandle hdRat;
{
return hdRat;
}
/****************************************************************************
**
*F SumRat( <hdL>, <hdR> ) . . . . . . . . . . . . . . sum of two rationals
**
** 'SumRat' returns the sum of two rationals <hdL> and <hdR>. Either
** operand may also be an integer. The sum is reduced.
**
** Is called from the 'Sum' binop, so both operands are already evaluated.
*/
TypHandle SumRat ( hdL, hdR )
TypHandle hdL, hdR;
{
TypHandle numL, denL; /* numerator and denominator left */
TypHandle numR, denR; /* numerator and denominator right */
TypHandle hdG1, hdG2; /* gcd of denominators */
TypHandle numS, denS; /* numerator and denominator sum */
TypHandle hdS; /* sum */
/* get numerator and denominator of the operands */
if ( TYPE(hdL) == T_RAT ) { numL = PTR(hdL)[0]; denL = PTR(hdL)[1]; }
else { numL = hdL; denL = INT_TO_HD(1); }
if ( TYPE(hdR) == T_RAT ) { numR = PTR(hdR)[0]; denR = PTR(hdR)[1]; }
else { numR = hdR; denR = INT_TO_HD(1); }
/* find the gcd of the denominators */
hdG1 = GcdInt( denL, denR );
/* nothing can cancel if the gcd is 1 */
if ( hdG1 == INT_TO_HD(1) ) {
numS = SumInt( ProdInt( numL, denR ), ProdInt( numR, denL ) );
denS = ProdInt( denL, denR );
}
/* a little bit more difficult otherwise */
else {
numS = SumInt( ProdInt( numL, QuoInt( denR, hdG1 ) ),
ProdInt( numR, QuoInt( denL, hdG1 ) ) );
hdG2 = GcdInt( numS, hdG1 );
numS = QuoInt( numS, hdG2 );
denS = ProdInt( QuoInt( denL, hdG1 ), QuoInt( denR, hdG2 ) );
}
/* make the fraction or, if possible, the integer */
if ( denS != INT_TO_HD(1) ) {
hdS = NewBag( T_RAT, 2 * SIZE_HD );
PTR(hdS)[0] = numS;
PTR(hdS)[1] = denS;
}
else {
hdS = numS;
}
/* return the result */
return hdS;
}
/****************************************************************************
**
*F DiffRat( <hdL>, <hdR> ) . . . . . . . . . . . difference of two rationals
**
** 'DiffRat' returns the difference of two rationals <hdL> and <hdR>.
** Either operand may also be an integer. The difference is reduced.
**
** Is called from the 'Diff' binop, so both operands are already evaluated.
*/
TypHandle DiffRat ( hdL, hdR )
TypHandle hdL, hdR;
{
TypHandle numL, denL; /* numerator and denominator left */
TypHandle numR, denR; /* numerator and denominator right */
TypHandle hdG1, hdG2; /* gcd of denominators */
TypHandle numD, denD; /* numerator and denominator diff */
TypHandle hdD; /* diff */
/* get numerator and denominator of the operands */
if ( TYPE(hdL) == T_RAT ) { numL = PTR(hdL)[0]; denL = PTR(hdL)[1]; }
else { numL = hdL; denL = INT_TO_HD(1); }
if ( TYPE(hdR) == T_RAT ) { numR = PTR(hdR)[0]; denR = PTR(hdR)[1]; }
else { numR = hdR; denR = INT_TO_HD(1); }
/* find the gcd of the denominators */
hdG1 = GcdInt( denL, denR );
/* nothing can cancel if the gcd is 1 */
if ( hdG1 == INT_TO_HD(1) ) {
numD = DiffInt( ProdInt( numL, denR ), ProdInt( numR, denL ) );
denD = ProdInt( denL, denR );
}
/* a little bit more difficult otherwise */
else {
numD = DiffInt( ProdInt( numL, QuoInt( denR, hdG1 ) ),
ProdInt( numR, QuoInt( denL, hdG1 ) ) );
hdG2 = GcdInt( numD, hdG1 );
numD = QuoInt( numD, hdG2 );
denD = ProdInt( QuoInt( denL, hdG1 ), QuoInt( denR, hdG2 ) );
}
/* make the fraction or, if possible, the integer */
if ( denD != INT_TO_HD(1) ) {
hdD = NewBag( T_RAT, 2 * SIZE_HD );
PTR(hdD)[0] = numD;
PTR(hdD)[1] = denD;
}
else {
hdD = numD;
}
/* return the result */
return hdD;
}
/****************************************************************************
**
*F ProdRat( <hdL>, <hdR> ) . . . . . . . . . . . . product of two rationals
**
** 'ProdRat' returns the product of two rationals <hdL> and <hdR>. Either
** operand may also be an integer. The product is reduced.
**
** Is called from the 'Prod' binop, so both operands are already evaluated.
*/
TypHandle ProdRat ( hdL, hdR )
TypHandle hdL, hdR;
{
TypHandle numL, denL; /* numerator and denominator left */
TypHandle numR, denR; /* numerator and denominator right */
TypHandle hdG1, hdG2; /* gcd of denominators */
TypHandle numP, denP; /* numerator and denominator prod */
TypHandle hdP; /* prod */
/* get numerator and denominator of the operands */
if ( TYPE(hdL) == T_RAT ) { numL = PTR(hdL)[0]; denL = PTR(hdL)[1]; }
else { numL = hdL; denL = INT_TO_HD(1); }
if ( TYPE(hdR) == T_RAT ) { numR = PTR(hdR)[0]; denR = PTR(hdR)[1]; }
else { numR = hdR; denR = INT_TO_HD(1); }
/* find the gcds */
hdG1 = GcdInt( numL, denR );
hdG2 = GcdInt( numR, denL );
/* nothing can cancel if the gcds are 1 */
if ( hdG1 == INT_TO_HD(1) && hdG2 == INT_TO_HD(1) ) {
numP = ProdInt( numL, numR );
denP = ProdInt( denL, denR );
}
/* a little bit more difficult otherwise */
else {
numP = ProdInt( QuoInt( numL, hdG1 ), QuoInt( numR, hdG2 ) );
denP = ProdInt( QuoInt( denL, hdG2 ), QuoInt( denR, hdG1 ) );
}
/* make the fraction or, if possible, the integer */
if ( denP != INT_TO_HD(1) ) {
hdP = NewBag( T_RAT, 2 * SIZE_HD );
PTR(hdP)[0] = numP;
PTR(hdP)[1] = denP;
}
else {
hdP = numP;
}
/* return the result */
return hdP;
}
/****************************************************************************
**
*F QuoRat( <hdL>, <hdR> ) . . . . . . . . . . . . quotient of two rationals
**
** 'QuoRat' returns the quotient of two rationals <hdL> and <hdR>. Either
** operand may also be an integer. The quotient is reduced.
**
** Is called from the 'Quo' binop, so both operands are already evaluated.
*/
TypHandle QuoRat ( hdL, hdR )
TypHandle hdL, hdR;
{
TypHandle numL, denL; /* numerator and denominator left */
TypHandle numR, denR; /* numerator and denominator right */
TypHandle hdG1, hdG2; /* gcd of denominators */
TypHandle numQ, denQ; /* numerator and denominator Qrod */
TypHandle hdQ; /* Qrod */
/* get numerator and denominator of the operands */
if ( TYPE(hdL) == T_RAT ) { numL = PTR(hdL)[0]; denL = PTR(hdL)[1]; }
else { numL = hdL; denL = INT_TO_HD(1); }
if ( TYPE(hdR) == T_RAT ) { numR = PTR(hdR)[0]; denR = PTR(hdR)[1]; }
else { numR = hdR; denR = INT_TO_HD(1); }
/* division by zero is an error */
if ( numR == INT_TO_HD(0) )
return Error("divisor must not be zero",0L,0L);
/* we multiply the left numerator with the right denominator */
/* so the right denominator should carry the sign of the right operand */
if ( (TYPE(numR)==T_INT && HD_TO_INT(numR)<0) || TYPE(numR)==T_INTNEG ) {
numR = ProdInt( INT_TO_HD(-1), numR );
denR = ProdInt( INT_TO_HD(-1), denR );
}
/* find the gcds */
hdG1 = GcdInt( numL, numR );
hdG2 = GcdInt( denR, denL );
/* nothing can cancel if the gcds are 1 */
if ( hdG1 == INT_TO_HD(1) && hdG2 == INT_TO_HD(1) ) {
numQ = ProdInt( numL, denR );
denQ = ProdInt( denL, numR );
}
/* a little bit more difficult otherwise */
else {
numQ = ProdInt( QuoInt( numL, hdG1 ), QuoInt( denR, hdG2 ) );
denQ = ProdInt( QuoInt( denL, hdG2 ), QuoInt( numR, hdG1 ) );
}
/* make the fraction or, if possible, the integer */
if ( denQ != INT_TO_HD(1) ) {
hdQ = NewBag( T_RAT, 2 * SIZE_HD );
PTR(hdQ)[0] = numQ;
PTR(hdQ)[1] = denQ;
}
else {
hdQ = numQ;
}
/* return the result */
return hdQ;
}
/****************************************************************************
**
*F ModRat( <hdL>, <hdL> ) . . . . . . . . remainder of fraction mod integer
**
** 'ModRat' returns the remainder of the fraction <hdL> modulo the integer
** <hdR>. The remainder is always an integer.
**
** '<r> / <s> mod <n>' yields the remainder of the fraction '<r> / <s>'
** modulo the integer '<n>'.
**
** The modular remainder of $r / s$ mod $n$ is defined as a $l$ from
** $0..n-1$ such that $r = l s$ mod $n$. As a special case $1 / s$ mod $n$
** is the modular inverse of $s$ modulo $n$.
**
** Note that the remainder will not exist if $s$ is not relative prime to
** $n$. However note that $4 / 6$ mod $32$ does exist (and is $22$), even
** though $6$ is not invertable modulo $32$, because the $2$ cancels.
**
** Another possible definition of $r/s$ mod $n$ would be a rational $t/s$
** such that $0 \<= t/s \< n$ and $r/s - t/s$ is a multiple of $n$. This is
** rarely needed while computing modular inverses is very useful.
**
** Is called from the 'Mod' binop, so both operands are already evaluated.
*/
TypHandle ModRat ( hdL, hdR )
TypHandle hdL, hdR;
{
TypHandle hdA, hdAL, hdB, hdBL, hdH, hdHL, hdQ;
/* make the integer positive */
if ( (TYPE(hdR)==T_INT && HD_TO_INT(hdR)<0) || TYPE(hdR)==T_INTNEG )
hdR = ProdInt( INT_TO_HD(-1), hdR );
/* invert the denominator with Euclids algorithm */
hdA = hdR; hdAL = INT_TO_HD(0);
hdB = PTR(hdL)[1]; hdBL = INT_TO_HD(1);
while ( hdB != INT_TO_HD(0) ) {
hdQ = QuoInt( hdA, hdB );
hdH = hdB; hdHL = hdBL;
hdB = DiffInt( hdA, ProdInt( hdQ, hdB ) );
hdBL = DiffInt( hdAL, ProdInt( hdQ, hdBL ) );
hdA = hdH; hdAL = hdHL;
}
/* check whether the denominator really was invertable mod <hdR> */
if ( hdA != INT_TO_HD(1) )
return Error("RatOps: denominator must be invertable",0L,0L);
/* return the remainder */
return ModInt( ProdInt( PTR(hdL)[0], hdAL ), hdR );
}
/****************************************************************************
**
*F PowRat( <hdL>, <hdR> ) . . . . . . raise a rational to an integer power
**
** 'PowRat' raises the rational <hdL> to the power given by the integer
** <hdR>. The power is reduced.
**
** Is called from the 'Pow' binop, so both operands are already evaluated.
*/
TypHandle PowRat ( hdL, hdR )
TypHandle hdL, hdR;
{
TypHandle numP, denP; /* numerator and denominator power */
TypHandle hdP; /* power */
/* raise numerator and denominator seperately */
numP = PowInt( PTR(hdL)[0], hdR );
denP = PowInt( PTR(hdL)[1], hdR );
/* if <hdR> == 0 return 1 */
if ( hdR == INT_TO_HD(0) ) {
hdP = INT_TO_HD(1);
}
/* if <hdR> == 1 return <hdL> */
else if ( hdR == INT_TO_HD(1) ) {
hdP = hdL;
}
/* if <hdR> is positive raise numberator and denominator seperately */
else if ( (TYPE(hdR)==T_INT&&0<HD_TO_INT(hdR)) || TYPE(hdR)==T_INTPOS ) {
numP = PowInt( PTR(hdL)[0], hdR );
denP = PowInt( PTR(hdL)[1], hdR );
hdP = NewBag( T_RAT, 2 * SIZE_HD );
PTR(hdP)[0] = numP;
PTR(hdP)[1] = denP;
}
/* if <hdR> is negative and numerator is 1 just power the denominator */
else if ( PTR(hdL)[0] == INT_TO_HD(1) ) {
hdP = PowInt( PTR(hdL)[1], ProdInt(INT_TO_HD(-1),hdR) );
}
/* if <hdR> is negative and numerator is -1 return (-1)^r * num(l) */
else if ( PTR(hdL)[0] == INT_TO_HD(-1) ) {
hdP = ProdInt( PowInt( PTR(hdL)[0], ProdInt(INT_TO_HD(-1),hdR) ),
PowInt( PTR(hdL)[1], ProdInt(INT_TO_HD(-1),hdR) ) );
}
/* if <hdR> is negative do both powers, take care of the sign */
else {
numP = PowInt( PTR(hdL)[1], ProdInt( INT_TO_HD(-1), hdR ) );
denP = PowInt( PTR(hdL)[0], ProdInt( INT_TO_HD(-1), hdR ) );
hdP = NewBag( T_RAT, 2 * SIZE_HD );
if ( (TYPE(denP) == T_INT && 0 < HD_TO_INT(denP))
|| TYPE(denP) == T_INTPOS ) {
PTR(hdP)[0] = numP;
PTR(hdP)[1] = denP;
}
else {
PTR(hdP)[0] = ProdInt( INT_TO_HD(-1), numP );
PTR(hdP)[1] = ProdInt( INT_TO_HD(-1), denP );
}
}
/* return the result */
return hdP;
}
/****************************************************************************
**
*F EqRat( <hdL>, <hdR> ) . . . . . . . . . . . . . . test if <ratL> = <ratR>
**
** 'EqRat' returns 'true' if the two rationals <ratL> and <ratR> are equal
** and 'false' otherwise.
**
** Is called from 'EvEq' binop, so both operands are already evaluated.
*/
TypHandle EqRat ( hdL, hdR )
TypHandle hdL, hdR;
{
TypHandle numL, denL; /* numerator and denominator left */
TypHandle numR, denR; /* numerator and denominator right */
/* get numerator and denominator of the operands */
if ( TYPE(hdL) == T_RAT ) { numL = PTR(hdL)[0]; denL = PTR(hdL)[1]; }
else { numL = hdL; denL = INT_TO_HD(1); }
if ( TYPE(hdR) == T_RAT ) { numR = PTR(hdR)[0]; denR = PTR(hdR)[1]; }
else { numR = hdR; denR = INT_TO_HD(1); }
/* two rationals are equal if numerators and denominators are equal */
if ( EqInt(numL,numR) == HdTrue && EqInt(denL,denR) == HdTrue )
return HdTrue;
else
return HdFalse;
}
/****************************************************************************
**
*F LtRat( <hdL>, <hdR> ) . . . . . . . . . . . . . . test if <ratL> < <ratR>
**
** 'LtRat' returns 'true' if the rational <ratL> is smaller than the
** rational <ratR> and 'false' otherwise. Either operand may be an integer.
**
** Is called from 'EvLt' binop, so both operands are already evaluated.
*/
TypHandle LtRat ( hdL, hdR )
TypHandle hdL, hdR;
{
TypHandle numL, denL; /* numerator and denominator left */
TypHandle numR, denR; /* numerator and denominator right */
/* get numerator and denominator of the operands */
if ( TYPE(hdL) == T_RAT ) { numL = PTR(hdL)[0]; denL = PTR(hdL)[1]; }
else { numL = hdL; denL = INT_TO_HD(1); }
if ( TYPE(hdR) == T_RAT ) { numR = PTR(hdR)[0]; denR = PTR(hdR)[1]; }
else { numR = hdR; denR = INT_TO_HD(1); }
/* a / b < c / d <=> a d < c b */
return LtInt( ProdInt( numL, denR ), ProdInt( numR, denL ) );
}
/****************************************************************************
**
*F PrRat( <hdRat> ) . . . . . . . . . . . . . . . . . . . print a rational
**
** 'PrRat' prints a rational in the standard form:
**
** <numerator> / <denominator>
*/
void PrRat ( hdRat )
TypHandle hdRat;
{
Pr("%>",0L,0L);
Print( PTR(hdRat)[0] );
Pr("%</%>",0L,0L);
Print( PTR(hdRat)[1] );
Pr("%<",0L,0L);
}
/****************************************************************************
**
*F FunIsRat( <hdCall> ) . . . . . . . . . internal function IsRat( <obj> )
**
** 'IsRat' returns 'true' if the object <obj> is a rational and 'false'
** otherwise. May cause an error if <obj> is an unbound variable.
*/
TypHandle FunIsRat ( hdCall )
TypHandle hdCall;
{
TypHandle hdObj;
/* evaluate and check the argument */
if ( SIZE(hdCall) != 2 * SIZE_HD )
return Error("usage: IsRat( <obj> )",0L,0L);
hdObj = EVAL( PTR(hdCall)[1] );
if ( hdObj == HdVoid )
return Error("IsRat: function must return a value",0L,0L);
/* return 'true' if <obj> is a rational and 'false' otherwise */
if ( TYPE(hdObj) == T_RAT || TYPE(hdObj) == T_INT
|| TYPE(hdObj) == T_INTPOS || TYPE(hdObj) == T_INTNEG )
return HdTrue;
else
return HdFalse;
}
/****************************************************************************
**
*F FunNumerator( <hdCall> ) . . . . . . . . . . internal function Numerator
**
** 'Numerator' returns the numerator of the rational argument.
*/
TypHandle FunNumerator ( hdCall )
TypHandle hdCall;
{
TypHandle hdRat;
/* evaluate and check the argument */
if ( SIZE(hdCall) != 2 * SIZE_HD )
return Error("usage: Numerator( <rat> )",0L,0L);
hdRat = EVAL( PTR(hdCall)[1] );
if ( hdRat == HdVoid )
return Error("Numerator: function must return a value",0L,0L);
if ( TYPE(hdRat) != T_RAT && TYPE(hdRat) != T_INT
&& TYPE(hdRat) != T_INTPOS && TYPE(hdRat) != T_INTNEG )
return Error("usage: Numerator( <rat> )",0L,0L);
/* return the numerator */
if ( TYPE(hdRat) == T_RAT )
return PTR(hdRat)[0];
else
return hdRat;
}
/****************************************************************************
**
*F FunDenominator( <hdCall> ) . . . . . . . . internal function Denominator
**
** 'Denominator' returns the denominator of the rational argument.
*/
TypHandle FunDenominator ( hdCall )
TypHandle hdCall;
{
TypHandle hdRat;
/* evaluate and check the argument */
if ( SIZE(hdCall) != 2 * SIZE_HD )
return Error("usage: Denominator( <rat> )",0L,0L);
hdRat = EVAL( PTR(hdCall)[1] );
if ( hdRat == HdVoid )
return Error("Denominator: function must return a value",0L,0L);
if ( TYPE(hdRat) != T_RAT && TYPE(hdRat) != T_INT
&& TYPE(hdRat) != T_INTPOS && TYPE(hdRat) != T_INTNEG )
return Error("usage: Denominator( <rat> )",0L,0L);
/* return the denominator */
if ( TYPE(hdRat) == T_RAT )
return PTR(hdRat)[1];
else
return INT_TO_HD(1);
}
/****************************************************************************
**
*F InitRat() . . . . . . . . . . . . . . . . initialize the rational package
**
** 'InitRat' initializes the rational package.
*/
void InitRat ()
{
InstEvFunc( T_RAT, EvRat );
InstPrFunc( T_RAT, PrRat );
TabSum[ T_RAT ][ T_RAT ] = SumRat;
TabSum[ T_INT ][ T_RAT ] = SumRat;
TabSum[ T_INTPOS ][ T_RAT ] = SumRat;
TabSum[ T_INTNEG ][ T_RAT ] = SumRat;
TabSum[ T_RAT ][ T_INT ] = SumRat;
TabSum[ T_RAT ][ T_INTPOS ] = SumRat;
TabSum[ T_RAT ][ T_INTNEG ] = SumRat;
TabDiff[ T_RAT ][ T_RAT ] = DiffRat;
TabDiff[ T_INT ][ T_RAT ] = DiffRat;
TabDiff[ T_INTPOS ][ T_RAT ] = DiffRat;
TabDiff[ T_INTNEG ][ T_RAT ] = DiffRat;
TabDiff[ T_RAT ][ T_INT ] = DiffRat;
TabDiff[ T_RAT ][ T_INTPOS ] = DiffRat;
TabDiff[ T_RAT ][ T_INTNEG ] = DiffRat;
TabProd[ T_RAT ][ T_RAT ] = ProdRat;
TabProd[ T_INT ][ T_RAT ] = ProdRat;
TabProd[ T_INTPOS ][ T_RAT ] = ProdRat;
TabProd[ T_INTNEG ][ T_RAT ] = ProdRat;
TabProd[ T_RAT ][ T_INT ] = ProdRat;
TabProd[ T_RAT ][ T_INTPOS ] = ProdRat;
TabProd[ T_RAT ][ T_INTNEG ] = ProdRat;
TabQuo[ T_INT ][ T_INT ] = QuoRat;
TabQuo[ T_INT ][ T_INTPOS ] = QuoRat;
TabQuo[ T_INT ][ T_INTNEG ] = QuoRat;
TabQuo[ T_INTPOS ][ T_INT ] = QuoRat;
TabQuo[ T_INTPOS ][ T_INTPOS ] = QuoRat;
TabQuo[ T_INTPOS ][ T_INTNEG ] = QuoRat;
TabQuo[ T_INTNEG ][ T_INT ] = QuoRat;
TabQuo[ T_INTNEG ][ T_INTPOS ] = QuoRat;
TabQuo[ T_INTNEG ][ T_INTNEG ] = QuoRat;
TabQuo[ T_RAT ][ T_RAT ] = QuoRat;
TabQuo[ T_INT ][ T_RAT ] = QuoRat;
TabQuo[ T_INTPOS ][ T_RAT ] = QuoRat;
TabQuo[ T_INTNEG ][ T_RAT ] = QuoRat;
TabQuo[ T_RAT ][ T_INT ] = QuoRat;
TabQuo[ T_RAT ][ T_INTPOS ] = QuoRat;
TabQuo[ T_RAT ][ T_INTNEG ] = QuoRat;
TabMod[ T_RAT ][ T_INT ] = ModRat;
TabMod[ T_RAT ][ T_INTPOS ] = ModRat;
TabMod[ T_RAT ][ T_INTNEG ] = ModRat;
TabPow[ T_RAT ][ T_INT ] = PowRat;
TabPow[ T_RAT ][ T_INTPOS ] = PowRat;
TabPow[ T_RAT ][ T_INTNEG ] = PowRat;
TabEq[ T_RAT ][ T_RAT ] = EqRat;
TabLt[ T_RAT ][ T_RAT ] = LtRat;
TabLt[ T_INT ][ T_RAT ] = LtRat;
TabLt[ T_INTPOS ][ T_RAT ] = LtRat;
TabLt[ T_INTNEG ][ T_RAT ] = LtRat;
TabLt[ T_RAT ][ T_INT ] = LtRat;
TabLt[ T_RAT ][ T_INTPOS ] = LtRat;
TabLt[ T_RAT ][ T_INTNEG ] = LtRat;
InstIntFunc( "IsRat", FunIsRat );
InstIntFunc( "Numerator", FunNumerator );
InstIntFunc( "Denominator", FunDenominator );
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.