/*
   This file is part of Numerix.  Numerix is free software; you can
   redistribute it and/or modify it under the terms of the GNU General
   Public License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA 
*/

/* +------------------------------------------------------------------------+
   |                                                                        |
   |             Entiers extensibles de longueur arbitraire                 |
   |                                                                        |
   |                      Interface publique C                              |
   |                                                                        |
   +------------------------------------------------------------------------+ */

/* M. Quercia, 11/08/2001 */

/* ne pas lire ce fichier deux fois */
#ifndef __c_long_int__
#define __c_long_int__

#include <stdlib.h>
#include "long_int.h"

typedef struct {     /* entier extensible  */
  longueur lmax;     /* capacité maximale  */
  entier   e;        /* entier associé     */
} * xint; 

/* signe et longueur */
#define Sgx(a) (((unsigned longueur)a->e.hd > (unsigned longueur)SIGN_m) ? SIGN_m : 0)
#define Lgx(x) ((x->e.hd) & LONG_m)

/* préfixe des fonctions publiques  */
#ifdef use_slong
#define xx(nom) sx_##nom
#else
#ifdef use_dlong
#define xx(nom) dx_##nom
#else
#define xx(nom) cx_##nom
#endif
#endif

/*
  allocation/désallocation, ne pas court-circuiter ces fonctions
  elles pourraient changer à l'avenir
*/
static inline xint xx(new)(void){return(NULL);}
static inline void xx(free)(xint *x){free(*x); *x=NULL;}

/* initialisation à partir d'un entier, d'un long ou d'une chaine */
xint xx(of_int)     (long a);
xint xx(of_xint)    (xint a);
xint xx(of_string)  (char *s);
void xx(copy)       (xint *x, xint b);
void xx(copy_int)   (xint *x, long a);
void xx(copy_string)(xint *x, char *s);

/* conversion entier -> chaine, désallouer la chaine par free */
static inline char *xx(string_of)(xint a) {return(xz(string_of)(&(a->e)));}
static inline void xx(free_string)(char *s) {free(s);}

/* accès à la structure binaire, lowbits, highbits et int_of retournent
  des mots de 31 bits seulement pour compatibilité avec Ocaml */
long xx(nbits)   (xint a);
long xx(lowbits) (xint a);
long xx(highbits)(xint a);
long xx(nth_word)(xint a, long n);
long xx(int_of)  (xint a);

/* comparaison */
static inline int xx(eq)     (xint a, xint b) {return((xz(cmp)(&(a->e), &(b->e)) == 0));}
static inline int xx(neq)    (xint a, xint b) {return((xz(cmp)(&(a->e), &(b->e)) != 0));}
static inline int xx(inf)    (xint a, xint b) {return((xz(cmp)(&(a->e), &(b->e)) <  0));}
static inline int xx(infeq)  (xint a, xint b) {return((xz(cmp)(&(a->e), &(b->e)) <= 0));}
static inline int xx(sup)    (xint a, xint b) {return((xz(cmp)(&(a->e), &(b->e)) >  0));}
static inline int xx(supeq)  (xint a, xint b) {return((xz(cmp)(&(a->e), &(b->e)) >= 0));}
static inline int xx(cmp)    (xint a, xint b) {return(xz(cmp) (&(a->e), &(b->e)));}
static inline int xx(sgn)    (xint a)         {return((Lgx(a) ? ((Sgx(a)) ? -1 : 1) : 0));}

int xx(cmp_1)(xint a, long b);
static inline int xx(eq_1)   (xint a, long b) {return((xx(cmp_1)(a, b) == 0));}
static inline int xx(neq_1)  (xint a, long b) {return((xx(cmp_1)(a, b) != 0));}
static inline int xx(inf_1)  (xint a, long b) {return((xx(cmp_1)(a, b) <  0));}
static inline int xx(infeq_1)(xint a, long b) {return((xx(cmp_1)(a, b) <= 0));}
static inline int xx(sup_1)  (xint a, long b) {return((xx(cmp_1)(a, b) >  0));}
static inline int xx(supeq_1)(xint a, long b) {return((xx(cmp_1)(a, b) >= 0));}

/* opérations usuelles */
void xx(abs)    (xint *x, xint a);
void xx(neg)    (xint *x, xint a);
void xx(add)    (xint *x, xint a, xint b);
void xx(add_1)  (xint *x, xint a, long b);
void xx(sub)    (xint *x, xint a, xint b);
void xx(sub_1)  (xint *x, xint a, long b);
void xx(shl)    (xint *x, xint a, long b);
void xx(shr)    (xint *x, xint a, long b);
void xx(split)  (xint *x, xint *y,xint a, long b);
void xx(join)   (xint *x, xint a, xint b, long c);
void xx(mul)    (xint *x, xint a, xint b);
void xx(mul_1)  (xint *x, xint a, long b);
void xx(sqr)    (xint *x, xint a);
void xx(quomod) (xint *x, xint *y,xint a, xint b);
void xx(quo)    (xint *x, xint a, xint b);
long xx(quomod_1) (xint *x, xint a, long b);
void xx(sqrt)   (xint *x, xint a);
void xx(pow)    (xint *x, xint a, long b);
void xx(powmod) (xint *x, xint a, xint b, xint c);
void xx(root)   (xint *x, xint a, long b);
void xx(fact)   (xint *x, long a);
void xx(gcd)    (xint *z, xint a, xint b);
void xx(gcd_ex) (xint *x, xint *y, xint *z, xint a, xint b);
void xx(cfrac)  (xint *r, xint *s, xint *x, xint *y, xint *z, xint a, xint b);

/* chronométrage */
void chrono(char *msg);

#endif /* ifndef __c_long_int__ */
