/****************************************************************************
**
*W  gmpints.h                   GAP source                     John McDermott
**                                                           
**                                                           
**
**
*Y  Copyright (C)  1996,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany
*Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
*Y  Copyright (C) 2002 The GAP Group
**
**  This file declares the functions handling gmp integers.
*/

#ifndef libGAP_GAP_GMPINTS_H
#define libGAP_GAP_GMPINTS_H

#ifdef USE_GMP

// GMP must be included outside of 'extern C'
#ifdef libGAP_GAP_IN_EXTERN_C
}
#endif
#include <gmp.h>
#ifdef libGAP_GAP_IN_EXTERN_C
extern "C" {
#endif

/****************************************************************************
**
*T  TypLimb . . . . . . . . . . . . . . . . . . . . . . .  type of a GMP Limb
**
**  
**  
*/
typedef mp_limb_t      libGAP_TypLimb;
typedef mp_size_t   libGAP_TypGMPSize;

#ifdef libGAP_SYS_IS_64_BIT
typedef libGAP_UInt4           libGAP_TypDigit;
#define libGAP_NR_HEX_DIGITS         8
#define libGAP_SaveLimb libGAP_SaveUInt8
#define libGAP_LoadLimb libGAP_LoadUInt8
#define libGAP_INTEGER_UNIT_SIZE 8
#define libGAP_INTEGER_ALLOCATION_SIZE 8
#else
typedef libGAP_UInt2           libGAP_TypDigit;
#define libGAP_NR_HEX_DIGITS         4
#define libGAP_SaveLimb libGAP_SaveUInt4
#define libGAP_LoadLimb libGAP_LoadUInt4
#define libGAP_INTEGER_UNIT_SIZE 4
#define libGAP_INTEGER_ALLOCATION_SIZE 4
#endif

#if GMP_LIMB_BITS != libGAP_NR_HEX_DIGITS * 8
#error Aborting compile: unexpected GMP limb size
#endif
#if GMP_NAIL_BITS != 0
#error Aborting compile: GAP does not support non-zero GMP nail size
#endif
#ifndef __GNU_MP_RELEASE
 #if __GMP_MP_RELEASE < 50002
 #error Aborting compile: GAP requires GMP 5.0.2 or newer
 #endif
#endif

#define libGAP_NR_DIGIT_BITS      (8 * sizeof(libGAP_TypDigit))
#define libGAP_INTBASE            (1L << libGAP_NR_DIGIT_BITS)
#define libGAP_NR_SMALL_INT_BITS  (2*libGAP_NR_DIGIT_BITS - 4)

#define libGAP_ADDR_INT(obj)          (  (libGAP_TypLimb *)libGAP_ADDR_OBJ(obj)                  )
#define libGAP_SIZE_INT(obj)          (  (libGAP_TypGMPSize)libGAP_SIZE_OBJ(obj)/sizeof(libGAP_TypLimb) )
/* SIZE_INT gives a result in limbs                                        */


/**************************************************************************
** The following two functions convert a C Int or UInt respectively into
** a GAP integer, either an immediate, small integer if possible or 
** otherwise a new GAP bag with TNUM T_INTPOS or T_INTNEG.
**
*F ObjInt_Int(Int i)
*F ObjInt_UInt(UInt i)
**
****************************************************************************/

libGAP_Obj libGAP_ObjInt_Int(libGAP_Int i);
libGAP_Obj libGAP_ObjInt_UInt(libGAP_UInt i);

/****************************************************************************
**
*/
extern  libGAP_Obj             libGAP_GMP_REDUCE ( 
                               libGAP_Obj                 gmp );
extern  libGAP_Obj             libGAP_GMP_NORMALIZE ( 
                               libGAP_Obj                 gmp );


/****************************************************************************
**
*F  PrintInt( <int> ) . . . . . . . . . . . . . . . print an integer constant
**
**  'PrintInt'  prints  the integer  <int>   in the  usual  decimal notation.
**  'PrintInt' handles objects of type 'T_INT', 'T_INTPOS' and 'T_INTNEG'.
*/
extern  void            libGAP_PrintInt (
            libGAP_Obj                 op );


/****************************************************************************
**
*F  EqInt( <gmpL>, <gmpR> ) . . . . . test if two integers are equal
**
**  'EqInt' returns 1  if  the two GMP integer arguments <gmpL> and  
**  <gmpR> are equal and 0 otherwise.
*/
extern  libGAP_Int             libGAP_EqInt ( 
                               libGAP_Obj                 opL,
                               libGAP_Obj                 opR );


/****************************************************************************
**
*F  LtInt( <gmpL>, <gmpR> )  test if an integer is less than another
**
**  'LtInt' returns 1 if the integer <gmpL> is strictly less than the 
**  integer <gmpR> and 0 otherwise.
*/
extern  libGAP_Int             libGAP_LtInt (
                               libGAP_Obj                 opL,
                               libGAP_Obj                 opR );


/****************************************************************************
**
*F  SumInt( <gmpL>, <gmpR> )  . . . . . . . . .  sum of two integers
**
**  'SumInt' returns the sum of the two integer arguments <gmpL> and
**  <gmpR>.
**
*/
extern  libGAP_Obj             libGAP_SumInt (
                                libGAP_Obj                 opL,
                                libGAP_Obj                 opR );

/****************************************************************************
**
*F  SumOrDiffInt( <gmpL>, <gmpR>, <sign> )  . . . . . . . sum of two integers
**
**  'SumOrDiffInt' returns the sum or difference of the two GMP arguments
**  <gmpL> and <gmpR>, depending whether sign is +1 or -1.
**
*/
extern  libGAP_Obj             libGAP_SumOrDiffInt (
                                libGAP_Obj                 opL,
                                libGAP_Obj                 opR,
                                libGAP_Int                 sign );


/****************************************************************************
**
*F  DiffInt( <gmpL>, <gmpR> ) . . . . difference of two GMP integers
**
**  'DiffInt' returns the difference of the two integer arguments <gmpL>
**  and <gmpR>.
**
*/
extern  libGAP_Obj             libGAP_DiffInt (
                                 libGAP_Obj                 opL,
                                 libGAP_Obj                 opR );

/****************************************************************************
**
*F  ProdInt( <gmpL>, <gmpR> ) . . . . .  product of two GMP integers
**
**  'ProdInt' returns the product of the two integer arguments <gmpL>
**  and <gmpR>.
**
*/
extern  libGAP_Obj             libGAP_ProdInt (
                                 libGAP_Obj                 opL,
                                 libGAP_Obj                 opR );


/****************************************************************************
**
*F  ModInt( <gmpL>, <gmpR> ) representant of res cl of a GMP integer
**
**  'ModInt' returns the smallest positive representant of the residue
**  class of the  integer  <gmpL>  modulo  the  integer  <gmpR>.
**
*/
extern  libGAP_Obj             libGAP_ModInt (
                                libGAP_Obj                 opL,
                                libGAP_Obj                 opR );


/****************************************************************************
**
*F  PowInt( <gmpL>, <gmpR> )  . . . . . . . . power of a GMP integer
**
**  'PowInt' returns the <gmpR>-th (a GMP int) power of the GMP integer
**  <gmpL>.
**
*/
extern  libGAP_Obj             libGAP_PowInt (
                                libGAP_Obj                 opL,
                                libGAP_Obj                 opR );


/****************************************************************************
**
*F  QuoInt( <gmpL>, <gmpR> )  . . . . . quotient of two GMP integers
**
**  'QuoInt' returns the integer part of the two integers <gmpL> and
**  <gmpR>.
**
*/
extern  libGAP_Obj             libGAP_QuoInt (
                                libGAP_Obj                 opL,
                                libGAP_Obj                 opR );


/****************************************************************************
**
*F  RemInt( <gmpL>, <gmpR> )  . . . .  remainder of two GMP integers
**
**  'RemInt' returns the remainder of the quotient of the GMP ints
**  <gmpL> and <gmpR>.
**
*/
extern  libGAP_Obj             libGAP_RemInt (
                                libGAP_Obj                 opL,
                                libGAP_Obj                 opR );


/****************************************************************************
**
*F  GcdInt( <gmpL>, <gmpR> )  . . . . . . .  gcd of two GMP integers
**
**  'GcdInt' returns the gcd of the two integers <gmpL> and <gmpR>.
*/
extern  libGAP_Obj             libGAP_GcdInt (
                                libGAP_Obj                 opL,
                                libGAP_Obj                 opR );


extern libGAP_Obj libGAP_FuncLog2Int( libGAP_Obj self, libGAP_Obj intnum);

extern libGAP_Obj libGAP_AInvInt ( libGAP_Obj gmp );

/****************************************************************************
**
*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
*/


/****************************************************************************
**
*F  InitInfoInt() . . . . . . . . . . . . . . . .  table of init functions
*/
libGAP_StructInitInfo * libGAP_InitInfoInt ( void );

#endif // USE_GMP

#endif // GAP_GMPINTS_H

/****************************************************************************
**
*E  gmpints.h . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
*/
