/****************************************************************************
**
** This file is part of GAP, a system for computational discrete algebra.
**
** Copyright of GAP belongs to its developers, whose names are too numerous
** to list here. Please refer to the COPYRIGHT file for details.
**
** SPDX-License-Identifier: GPL-2.0-or-later
**
** 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 is relatively prime to 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 unnecessary 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'.
*/
#include "rational.h"
#include "ariths.h"
#include "bool.h"
#include "error.h"
#include "integer.h"
#include "io.h"
#include "modules.h"
#include "opers.h"
#include "saveload.h"
#if defined(DEBUG_RATIONALS)
#define CHECK_RAT(rat) \
if (TNUM_OBJ(rat) == T_RAT && \
(!LtInt(INTOBJ_INT(1), DEN_RAT(rat)) || \
GcdInt(NUM_RAT(rat), DEN_RAT(rat)) != INTOBJ_INT(1))) \
ErrorQuit(
"bad rational", 0, 0)
#else
#define CHECK_RAT(rat)
#endif
#define RequireRational(funcname, op) \
RequireArgumentCondition(funcname, op, \
TNUM_OBJ(op) == T_RAT || IS_INT(op), \
"must be a rational")
static inline Obj MakeRat(Obj num, Obj den)
{
Obj rat = NewBag(T_RAT, 2 *
sizeof(Obj));
SET_NUM_RAT(rat, num);
SET_DEN_RAT(rat, den);
return rat;
}
/****************************************************************************
**
*F TypeRat( <rat> ) . . . . . . . . . . . . . . . . . . type of a rational
**
** 'TypeRat' returns the type of the rational <rat>.
**
** 'TypeRat' is the function in 'TypeObjFuncs' for rationals.
*/
static Obj TYPE_RAT_POS;
static Obj TYPE_RAT_NEG;
static Obj TypeRat(Obj rat)
{
Obj num;
CHECK_RAT(rat);
num = NUM_RAT(rat);
return IS_NEG_INT(num) ? TYPE_RAT_NEG : TYPE_RAT_POS;
}
/****************************************************************************
**
*F PrintRat( <rat> ) . . . . . . . . . . . . . . . . . . . print a rational
**
** 'PrintRat' prints a rational <rat> in the form
**
** <numerator> / <denominator>
*/
static void PrintRat(Obj rat)
{
Pr(
"%>", 0, 0);
PrintObj( NUM_RAT(rat) );
Pr(
"%%>", 0, 0);
PrintObj( DEN_RAT(rat) );
Pr(
"%<", 0, 0);
}
/****************************************************************************
**
*F EqRat( <opL>, <opR> ) . . . . . . . . . . . . . . test if <ratL> = <ratR>
**
** 'EqRat' returns 'true' if the two rationals <ratL> and <ratR> are equal
** and 'false' otherwise.
*/
static Int EqRat(Obj opL, Obj opR)
{
Obj numL, denL;
// numerator and denominator left
Obj numR, denR;
// numerator and denominator right
CHECK_RAT(opL);
CHECK_RAT(opR);
// get numerator and denominator of the operands
numL = NUM_RAT(opL);
denL = DEN_RAT(opL);
numR = NUM_RAT(opR);
denR = DEN_RAT(opR);
// compare the numerators
if ( ! EQ( numL, numR ) ) {
return 0;
}
// compare the denominators
if ( ! EQ( denL, denR ) ) {
return 0;
}
// no differences found, they must be equal
return 1;
}
/****************************************************************************
**
*F LtRat( <opL>, <opR> ) . . . . . . . . . . . . . . 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.
*/
static Int LtRat(Obj opL, Obj opR)
{
Obj numL, denL;
// numerator and denominator left
Obj numR, denR;
// numerator and denominator right
CHECK_RAT(opL);
CHECK_RAT(opR);
// get numerator and denominator of the operands
if ( TNUM_OBJ(opL) == T_RAT ) {
numL = NUM_RAT(opL);
denL = DEN_RAT(opL);
}
else {
numL = opL;
denL = INTOBJ_INT(1);
}
if ( TNUM_OBJ(opR) == T_RAT ) {
numR = NUM_RAT(opR);
denR = DEN_RAT(opR);
}
else {
numR = opR;
denR = INTOBJ_INT(1);
}
// a / b < c / d <=> a d < c b
return LtInt( ProdInt( numL, denR ), ProdInt( numR, denL ) );
}
/****************************************************************************
**
*F SumRat( <opL>, <opR> ) . . . . . . . . . . . . . . sum of two rationals
**
** 'SumRat' returns the sum of two rationals <opL> and <opR>. Either
** operand may also be an integer. The sum is reduced.
*/
static Obj SumRat(Obj opL, Obj opR)
{
Obj numL, denL;
// numerator and denominator left
Obj numR, denR;
// numerator and denominator right
Obj gcd1, gcd2;
// gcd of denominators
Obj numS, denS;
// numerator and denominator sum
Obj sum;
// sum
CHECK_RAT(opL);
CHECK_RAT(opR);
// get numerator and denominator of the operands
if ( TNUM_OBJ(opL) == T_RAT ) {
numL = NUM_RAT(opL);
denL = DEN_RAT(opL);
}
else {
numL = opL;
denL = INTOBJ_INT(1);
}
if ( TNUM_OBJ(opR) == T_RAT ) {
numR = NUM_RAT(opR);
denR = DEN_RAT(opR);
}
else {
numR = opR;
denR = INTOBJ_INT(1);
}
// find the gcd of the denominators
gcd1 = GcdInt( denL, denR );
// nothing can cancel if the gcd is 1
if (gcd1 == INTOBJ_INT(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, gcd1 ) ),
ProdInt( numR, QuoInt( denL, gcd1 ) ) );
gcd2 = GcdInt( numS, gcd1 );
numS = QuoInt( numS, gcd2 );
denS = ProdInt( QuoInt( denL, gcd1 ), QuoInt( denR, gcd2 ) );
}
// make the fraction or, if possible, the integer
if (denS != INTOBJ_INT(1)) {
sum = MakeRat(numS, denS);
}
else {
sum = numS;
}
CHECK_RAT(sum);
return sum;
}
/****************************************************************************
**
*F ZeroRat(<op>) . . . . . . . . . . . . . . . . . . . . zero of a rational
*/
static Obj ZeroRat(Obj op)
{
return INTOBJ_INT(0);
}
/****************************************************************************
**
*F AInvRat(<op>) . . . . . . . . . . . . . . additive inverse of a rational
*/
static Obj AInvRat(Obj op)
{
Obj res;
Obj tmp;
CHECK_RAT(op);
tmp = AInvInt( NUM_RAT(op) );
res = MakeRat(tmp, DEN_RAT(op));
CHECK_RAT(res);
return res;
}
/****************************************************************************
**
*F AbsRat(<op>) . . . . . . . . . . . . . . . . absolute value of a rational
*/
static Obj AbsRat(Obj op)
{
Obj res;
Obj tmp;
CHECK_RAT(op);
tmp = AbsInt( NUM_RAT(op) );
if ( tmp == NUM_RAT(op))
return op;
res = MakeRat(tmp, DEN_RAT(op));
CHECK_RAT(res);
return res;
}
static Obj FuncABS_RAT(Obj self, Obj op)
{
RequireRational(SELF_NAME, op);
return (TNUM_OBJ(op) == T_RAT) ? AbsRat(op) : AbsInt(op);
}
/****************************************************************************
**
*F SignRat(<op>) . . . . . . . . . . . . . . . . . . . . sign of a rational
*/
static Obj SignRat(Obj op)
{
CHECK_RAT(op);
return SignInt( NUM_RAT(op) );
}
static Obj FuncSIGN_RAT(Obj self, Obj op)
{
RequireRational(SELF_NAME, op);
return (TNUM_OBJ(op) == T_RAT) ? SignRat(op) : SignInt(op);
}
/****************************************************************************
**
*F DiffRat( <opL>, <opR> ) . . . . . . . . . . . difference of two rationals
**
** 'DiffRat' returns the difference of two rationals <opL> and <opR>.
** Either operand may also be an integer. The difference is reduced.
*/
static Obj DiffRat(Obj opL, Obj opR)
{
Obj numL, denL;
// numerator and denominator left
Obj numR, denR;
// numerator and denominator right
Obj gcd1, gcd2;
// gcd of denominators
Obj numD, denD;
// numerator and denominator diff
Obj dif;
// diff
CHECK_RAT(opL);
CHECK_RAT(opR);
// get numerator and denominator of the operands
if ( TNUM_OBJ(opL) == T_RAT ) {
numL = NUM_RAT(opL);
denL = DEN_RAT(opL);
}
else {
numL = opL;
denL = INTOBJ_INT(1);
}
if ( TNUM_OBJ(opR) == T_RAT ) {
numR = NUM_RAT(opR);
denR = DEN_RAT(opR);
}
else {
numR = opR;
denR = INTOBJ_INT(1);
}
// find the gcd of the denominators
gcd1 = GcdInt( denL, denR );
// nothing can cancel if the gcd is 1
if (gcd1 == INTOBJ_INT(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, gcd1 ) ),
ProdInt( numR, QuoInt( denL, gcd1 ) ) );
gcd2 = GcdInt( numD, gcd1 );
numD = QuoInt( numD, gcd2 );
denD = ProdInt( QuoInt( denL, gcd1 ), QuoInt( denR, gcd2 ) );
}
// make the fraction or, if possible, the integer
if (denD != INTOBJ_INT(1)) {
dif = MakeRat(numD, denD);
}
else {
dif = numD;
}
CHECK_RAT(dif);
return dif;
}
/****************************************************************************
**
*F ProdRat( <opL>, <opR> ) . . . . . . . . . . . . product of two rationals
**
** 'ProdRat' returns the product of two rationals <opL> and <opR>. Either
** operand may also be an integer. The product is reduced.
*/
static Obj ProdRat(Obj opL, Obj opR)
{
Obj numL, denL;
// numerator and denominator left
Obj numR, denR;
// numerator and denominator right
Obj gcd1, gcd2;
// gcd of denominators
Obj numP, denP;
// numerator and denominator prod
Obj prd;
// prod
CHECK_RAT(opL);
CHECK_RAT(opR);
// get numerator and denominator of the operands
if ( TNUM_OBJ(opL) == T_RAT ) {
numL = NUM_RAT(opL);
denL = DEN_RAT(opL);
}
else {
numL = opL;
denL = INTOBJ_INT(1);
}
if ( TNUM_OBJ(opR) == T_RAT ) {
numR = NUM_RAT(opR);
denR = DEN_RAT(opR);
}
else {
numR = opR;
denR = INTOBJ_INT(1);
}
// find the gcds
gcd1 = GcdInt( numL, denR );
gcd2 = GcdInt( numR, denL );
// nothing can cancel if the gcds are 1
if (gcd1 == INTOBJ_INT(1) && gcd2 == INTOBJ_INT(1)) {
numP = ProdInt( numL, numR );
denP = ProdInt( denL, denR );
}
// a little bit more difficult otherwise
else {
numP = ProdInt( QuoInt( numL, gcd1 ), QuoInt( numR, gcd2 ) );
denP = ProdInt( QuoInt( denL, gcd2 ), QuoInt( denR, gcd1 ) );
}
// make the fraction or, if possible, the integer
if (denP != INTOBJ_INT(1)) {
prd = MakeRat(numP, denP);
}
else {
prd = numP;
}
CHECK_RAT(prd);
return prd;
}
/****************************************************************************
**
*F OneRat(<op>) . . . . . . . . . . . . . . . . . . . . . one of a rational
*/
static Obj OneRat(Obj op)
{
return INTOBJ_INT(1);
}
/****************************************************************************
**
*F InvRat(<op>) . . . . . . . . . . . . . . . . . . . inverse of a rational
*/
static Obj QuoRat(Obj opL, Obj opR);
static Obj InvRat(Obj op)
{
Obj res;
CHECK_RAT(op);
if (op == INTOBJ_INT(0))
return Fail;
res = QuoRat(INTOBJ_INT(1), op);
CHECK_RAT(res);
return res;
}
/****************************************************************************
**
*F QuoRat( <opL>, <opR> ) . . . . . . . . . . . . quotient of two rationals
**
** 'QuoRat' returns the quotient of two rationals <opL> and <opR>. Either
** operand may also be an integer. The quotient is reduced.
*/
static Obj QuoRat(Obj opL, Obj opR)
{
Obj numL, denL;
// numerator and denominator left
Obj numR, denR;
// numerator and denominator right
Obj gcd1, gcd2;
// gcd of denominators
Obj numQ, denQ;
// numerator and denominator Qrod
Obj quo;
// Qrod
CHECK_RAT(opL);
CHECK_RAT(opR);
// get numerator and denominator of the operands
if ( TNUM_OBJ(opL) == T_RAT ) {
numL = NUM_RAT(opL);
denL = DEN_RAT(opL);
}
else {
numL = opL;
denL = INTOBJ_INT(1);
}
if ( TNUM_OBJ(opR) == T_RAT ) {
numR = NUM_RAT(opR);
denR = DEN_RAT(opR);
}
else {
numR = opR;
denR = INTOBJ_INT(1);
}
// division by zero is an error
if (numR == INTOBJ_INT(0)) {
ErrorMayQuit(
"Rational operations: must not be zero", 0, 0);
}
// we multiply the left numerator with the right denominator
// so the right denominator should carry the sign of the right operand
if ( IS_NEG_INT(numR) ) {
numR = AInvInt( numR );
denR = AInvInt( denR );
}
// find the gcds
gcd1 = GcdInt( numL, numR );
gcd2 = GcdInt( denR, denL );
// nothing can cancel if the gcds are 1
if (gcd1 == INTOBJ_INT(1) && gcd2 == INTOBJ_INT(1)) {
numQ = ProdInt( numL, denR );
denQ = ProdInt( denL, numR );
}
// a little bit more difficult otherwise
else {
numQ = ProdInt( QuoInt( numL, gcd1 ), QuoInt( denR, gcd2 ) );
denQ = ProdInt( QuoInt( denL, gcd2 ), QuoInt( numR, gcd1 ) );
}
// make the fraction or, if possible, the integer
if (denQ != INTOBJ_INT(1)) {
quo = MakeRat(numQ, denQ);
}
else {
quo = numQ;
}
CHECK_RAT(quo);
return quo;
}
/****************************************************************************
**
*F ModRat( <opL>, <n> ) . . . . . . . . remainder of fraction mod integer
**
** 'ModRat' returns the remainder of the fraction <opL> modulo the integer
** <n>. The remainder is always an integer.
**
** '<r> / <s> mod <n>' yields the remainder of the fraction '<p> / <q>'
** modulo the integer '<n>', where '<p> / <q>' is the reduced form of
** '<r> / <s>'.
**
** The modular remainder of $r / s$ mod $n$ is defined to be the integer $k$
** in $0 .. n-1$ such that $p = k q$ mod $n$, where $p = r / gcd(r, s)$ and
** $q = s / gcd(r, s)$. In particular, $1 / s$ mod $n$ is the modular
** inverse of $s$ modulo $n$, whenever $s$ and $n$ are relatively prime.
**
** Note that the remainder will not exist if $s / gcd(r, s)$ is not
** relatively prime to $n$. Note that $4 / 6$ mod $32$ does exist (and is
** $22$), even though $6$ is not invertible 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.
*/
static Obj ModRat(Obj opL, Obj n)
{
// invert the denominator
Obj d = InverseModInt( DEN_RAT(opL), n );
// check whether the denominator of <opL> really was invertible mod <n> */
if ( d == Fail ) {
ErrorMayQuit(
"ModRat: for / mod , /gcd(,) and must be coprime",
0, 0 );
}
// return the remainder
return ModInt( ProdInt( NUM_RAT(opL), d ), n );
}
/****************************************************************************
**
*F PowRat( <opL>, <opR> ) . . . . . . raise a rational to an integer power
**
** 'PowRat' raises the rational <opL> to the power given by the integer
** <opR>. The power is reduced.
*/
static Obj PowRat(Obj opL, Obj opR)
{
Obj numP, denP;
// numerator and denominator power
Obj pow;
// power
CHECK_RAT(opL);
// if <opR> == 0 return 1
if (opR == INTOBJ_INT(0)) {
pow = INTOBJ_INT(1);
}
// if <opR> == 1 return <opL>
else if (opR == INTOBJ_INT(1)) {
pow = opL;
}
// if <opR> is positive raise numerator and denominator separately
else if ( IS_POS_INT(opR) ) {
numP = PowInt( NUM_RAT(opL), opR );
denP = PowInt( DEN_RAT(opL), opR );
pow = MakeRat(numP, denP);
}
// if <opR> is negative and numerator is 1 just power the denominator
else if (NUM_RAT(opL) == INTOBJ_INT(1)) {
pow = PowInt( DEN_RAT(opL), AInvInt( opR ) );
}
// if <opR> is negative and numerator is -1 return (-1)^r * num(l)
else if (NUM_RAT(opL) == INTOBJ_INT(-1)) {
numP = PowInt( NUM_RAT(opL), AInvInt( opR ) );
denP = PowInt( DEN_RAT(opL), AInvInt( opR ) );
pow = ProdInt(numP, denP);
}
// if <opR> is negative do both powers, take care of the sign
else {
numP = PowInt( DEN_RAT(opL), AInvInt( opR ) );
denP = PowInt( NUM_RAT(opL), AInvInt( opR ) );
if (IS_NEG_INT(denP)) {
numP = AInvInt(numP);
denP = AInvInt(denP);
}
pow = MakeRat(numP, denP);
}
CHECK_RAT(pow);
return pow;
}
/****************************************************************************
**
*F FiltIS_RAT(<self>,<val>) . . . . . . . . . . . . . is a value a rational
**
** 'FiltIS_RAT' implements the internal function 'IsRat'.
**
** 'IsRat( <val> )'
**
** 'IsRat' returns 'true' if the value <val> is a rational and 'false'
** otherwise.
*/
static Obj IsRatFilt;
static Obj FiltIS_RAT(Obj self, Obj val)
{
// return 'true' if <val> is a rational and 'false' otherwise
if ( TNUM_OBJ(val) == T_RAT || IS_INT(val) ) {
return True;
}
else if ( TNUM_OBJ(val) < FIRST_EXTERNAL_TNUM ) {
return False;
}
else {
return DoFilter( self, val );
}
}
/****************************************************************************
**
*F FuncNUMERATOR_RAT(<self>,<rat>) . . . . . . . . . numerator of a rational
**
** 'FuncNUMERATOR_RAT' implements the internal function 'NumeratorRat'.
**
** 'NumeratorRat( <rat> )'
**
** 'NumeratorRat' returns the numerator of the rational <rat>.
*/
static Obj FuncNUMERATOR_RAT(Obj self, Obj rat)
{
RequireRational(SELF_NAME, rat);
if ( TNUM_OBJ(rat) == T_RAT ) {
return NUM_RAT(rat);
}
else {
return rat;
}
}
/****************************************************************************
**
*F FuncDENOMINATOR_RAT(<self>,<rat>) . . . . . . . denominator of a rational
**
** 'FuncDENOMINATOR_RAT' implements the internal function 'DenominatorRat'.
**
** 'DenominatorRat( <rat> )'
**
** 'DenominatorRat' returns the denominator of the rational <rat>.
*/
static Obj FuncDENOMINATOR_RAT(Obj self, Obj rat)
{
RequireRational(SELF_NAME, rat);
if ( TNUM_OBJ(rat) == T_RAT ) {
return DEN_RAT(rat);
}
else {
return INTOBJ_INT(1);
}
}
/****************************************************************************
**
*F SaveRat( <rat> )
**
*/
#ifdef GAP_ENABLE_SAVELOAD
static void SaveRat(Obj rat)
{
SaveSubObj(NUM_RAT(rat));
SaveSubObj(DEN_RAT(rat));
}
#endif
/****************************************************************************
**
*F LoadRat( <rat> )
**
*/
#ifdef GAP_ENABLE_SAVELOAD
static void LoadRat(Obj rat)
{
SET_NUM_RAT(rat, LoadSubObj());
SET_DEN_RAT(rat, LoadSubObj());
}
#endif
/****************************************************************************
**
*F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
*/
/****************************************************************************
**
*V GVarFilts . . . . . . . . . . . . . . . . . . . list of filters to export
*/
static StructGVarFilt GVarFilts [] = {
GVAR_FILT(IS_RAT,
"obj", &IsRatFilt),
{ 0, 0, 0, 0, 0 }
};
/****************************************************************************
**
*V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
*/
static StructGVarFunc GVarFuncs[] = {
GVAR_FUNC_1ARGS(NUMERATOR_RAT, rat),
GVAR_FUNC_1ARGS(DENOMINATOR_RAT, rat),
GVAR_FUNC_1ARGS(ABS_RAT, op),
GVAR_FUNC_1ARGS(SIGN_RAT, op),
{ 0, 0, 0, 0, 0 }
};
/****************************************************************************
**
*V BagNames . . . . . . . . . . . . . . . . . . . . . . . list of bag names
*/
static StructBagNames BagNames[] = {
{ T_RAT,
"rational" },
{ -1,
"" }
};
/****************************************************************************
**
*F InitKernel( <module> ) . . . . . . . . initialise kernel data structures
*/
static Int InitKernel (
StructInitInfo * module )
{
// set the bag type names (for error messages and debugging)
InitBagNamesFromTable( BagNames );
// install the marking function
//
// MarkTwoSubBags() is faster for Gasman, but MarkAllSubBags() is
// more space-efficient for the Boehm GC and does not incur a
// speed penalty.
#ifdef USE_GASMAN
InitMarkFuncBags( T_RAT, MarkTwoSubBags );
#else
InitMarkFuncBags( T_RAT, MarkAllSubBags );
#endif
// install the type functions
ImportGVarFromLibrary(
"TYPE_RAT_POS", &TYPE_RAT_POS );
ImportGVarFromLibrary(
"TYPE_RAT_NEG", &TYPE_RAT_NEG );
TypeObjFuncs[ T_RAT ] = TypeRat;
// init filters and functions
InitHdlrFiltsFromTable( GVarFilts );
InitHdlrFuncsFromTable( GVarFuncs );
#ifdef GAP_ENABLE_SAVELOAD
// install a saving functions
SaveObjFuncs[ T_RAT ] = SaveRat;
LoadObjFuncs[ T_RAT ] = LoadRat;
#endif
// install the printer
PrintObjFuncs[ T_RAT ] = PrintRat;
// install the comparisons
EqFuncs [ T_RAT ][ T_RAT ] = EqRat;
LtFuncs [ T_RAT ][ T_RAT ] = LtRat;
LtFuncs [ T_INT ][ T_RAT ] = LtRat;
LtFuncs [ T_INTPOS ][ T_RAT ] = LtRat;
LtFuncs [ T_INTNEG ][ T_RAT ] = LtRat;
LtFuncs [ T_RAT ][ T_INT ] = LtRat;
LtFuncs [ T_RAT ][ T_INTPOS ] = LtRat;
LtFuncs [ T_RAT ][ T_INTNEG ] = LtRat;
// install the arithmetic operations
ZeroSameMutFuncs[T_RAT] = ZeroRat;
AInvSameMutFuncs[T_RAT] = AInvRat;
AInvMutFuncs[ T_RAT ] = AInvRat;
OneFuncs [ T_RAT ] = OneRat;
OneSameMut[T_RAT] = OneRat;
InvFuncs [ T_INT ] = InvRat;
InvFuncs [ T_INTPOS ] = InvRat;
InvFuncs [ T_INTNEG ] = InvRat;
InvFuncs [ T_RAT ] = InvRat;
InvSameMutFuncs[T_INT] = InvRat;
InvSameMutFuncs[T_INTPOS] = InvRat;
InvSameMutFuncs[T_INTNEG] = InvRat;
InvSameMutFuncs[T_RAT] = InvRat;
SumFuncs [ T_RAT ][ T_RAT ] = SumRat;
SumFuncs [ T_INT ][ T_RAT ] = SumRat;
SumFuncs [ T_INTPOS ][ T_RAT ] = SumRat;
SumFuncs [ T_INTNEG ][ T_RAT ] = SumRat;
SumFuncs [ T_RAT ][ T_INT ] = SumRat;
SumFuncs [ T_RAT ][ T_INTPOS ] = SumRat;
SumFuncs [ T_RAT ][ T_INTNEG ] = SumRat;
DiffFuncs[ T_RAT ][ T_RAT ] = DiffRat;
DiffFuncs[ T_INT ][ T_RAT ] = DiffRat;
DiffFuncs[ T_INTPOS ][ T_RAT ] = DiffRat;
DiffFuncs[ T_INTNEG ][ T_RAT ] = DiffRat;
DiffFuncs[ T_RAT ][ T_INT ] = DiffRat;
DiffFuncs[ T_RAT ][ T_INTPOS ] = DiffRat;
DiffFuncs[ T_RAT ][ T_INTNEG ] = DiffRat;
ProdFuncs[ T_RAT ][ T_RAT ] = ProdRat;
ProdFuncs[ T_INT ][ T_RAT ] = ProdRat;
ProdFuncs[ T_INTPOS ][ T_RAT ] = ProdRat;
ProdFuncs[ T_INTNEG ][ T_RAT ] = ProdRat;
ProdFuncs[ T_RAT ][ T_INT ] = ProdRat;
ProdFuncs[ T_RAT ][ T_INTPOS ] = ProdRat;
ProdFuncs[ T_RAT ][ T_INTNEG ] = ProdRat;
QuoFuncs [ T_INT ][ T_INT ] = QuoRat;
QuoFuncs [ T_INT ][ T_INTPOS ] = QuoRat;
QuoFuncs [ T_INT ][ T_INTNEG ] = QuoRat;
QuoFuncs [ T_INTPOS ][ T_INT ] = QuoRat;
QuoFuncs [ T_INTPOS ][ T_INTPOS ] = QuoRat;
QuoFuncs [ T_INTPOS ][ T_INTNEG ] = QuoRat;
QuoFuncs [ T_INTNEG ][ T_INT ] = QuoRat;
QuoFuncs [ T_INTNEG ][ T_INTPOS ] = QuoRat;
QuoFuncs [ T_INTNEG ][ T_INTNEG ] = QuoRat;
QuoFuncs [ T_RAT ][ T_RAT ] = QuoRat;
QuoFuncs [ T_INT ][ T_RAT ] = QuoRat;
QuoFuncs [ T_INTPOS ][ T_RAT ] = QuoRat;
QuoFuncs [ T_INTNEG ][ T_RAT ] = QuoRat;
QuoFuncs [ T_RAT ][ T_INT ] = QuoRat;
QuoFuncs [ T_RAT ][ T_INTPOS ] = QuoRat;
QuoFuncs [ T_RAT ][ T_INTNEG ] = QuoRat;
ModFuncs [ T_RAT ][ T_INT ] = ModRat;
ModFuncs [ T_RAT ][ T_INTPOS ] = ModRat;
ModFuncs [ T_RAT ][ T_INTNEG ] = ModRat;
PowFuncs [ T_RAT ][ T_INT ] = PowRat;
PowFuncs [ T_RAT ][ T_INTPOS ] = PowRat;
PowFuncs [ T_RAT ][ T_INTNEG ] = PowRat;
#ifdef HPCGAP
MakeBagTypePublic(T_RAT);
#endif
return 0;
}
/****************************************************************************
**
*F InitLibrary( <module> ) . . . . . . . initialise library data structures
*/
static Int InitLibrary (
StructInitInfo * module )
{
// init filters and functions
InitGVarFiltsFromTable( GVarFilts );
InitGVarFuncsFromTable( GVarFuncs );
return 0;
}
/****************************************************************************
**
*F InitInfoRat() . . . . . . . . . . . . . . . . . . table of init functions
*/
static StructInitInfo module = {
// init struct using C99 designated initializers; for a full list of
// fields, please refer to the definition of StructInitInfo
.type = MODULE_BUILTIN,
.name =
"rational",
.initKernel = InitKernel,
.initLibrary = InitLibrary,
};
StructInitInfo * InitInfoRat (
void )
{
return &module;
}