//
// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : bigint.h 
// Author      : Thomas Papanikolaou (TP)
// Last change : TP, Feb 7 1995, initial version
//		 AH, Sep 25 1996,
//		     Changed the return-value type of all
//		     functions which answer yes/no to bool.
//		 MM, Sep 25 1996,
//		     Changed the return-value type of the
//		     postfix operators from bigint & to bigint
//		     because the return-value must be a local variable.
//		 MM, Oct 25 1996,
//		     Replaced bigint(double) by the corresponding assign(double) function.
//		     THe old version confused programmers when adding a bigint and a double,
//		     because the expect bigint to work in the same way like int.
//

#ifndef LIDIA_BIGINT_H
#define LIDIA_BIGINT_H

#include <LiDIA/bigint_def.h>
#include <LiDIA/xdouble.h>

#if defined(__STRICT_ANSI__) || defined(LIDIA_STRICT_ANSI_CPP)
#define and l_and 
#define or l_or
#define xor l_xor
#define not l_not
#endif

class bigint
{

  /**
  ** the C type we use to represent a bigint
  **/

  integer_type_name I;

            public:

  /**
  ** constructors and destructor; we could leave out some of these
  **/

            bigint();
            bigint(int i);
            bigint(long l);
            bigint(unsigned long ul);
            bigint(const bigint & a);
           ~bigint();

  /**
  ** inline member functions
  **/
  
  int bit(unsigned int i) const;
  lidia_size_t length() const;
  lidia_size_t bit_length() const;
  int sign() const;
  bool is_odd() const;
  bool is_even() const;

#ifndef HEADBANGER

  bool is_positive() const;
  bool is_negative() const;
  bool is_zero() const;
  bool is_gt_zero() const;
  bool is_ge_zero() const;
  bool is_lt_zero() const;
  bool is_le_zero() const;
  bool is_one() const;
  bool intify(int &i) const;
  bool longify(long &i) const;
  int abs_compare(const bigint & a) const;
  int compare(const bigint & a) const;
  unsigned long most_significant_digit() const;
  unsigned long least_significant_digit() const;

  /**
  ** the next two definitions are needed by bigfloat
  **/

  //static const unsigned long radix();
  static const double radix();
  static const int bits_per_digit();

  void absolute_value();
  void abs();
  void negate();
  void assign_zero();
  void assign_one();
  void assign(int i);
  void assign(long ui);
  void assign(unsigned long ui);
  void assign(double);
  void assign(const bigint & a);
  void multiply_by_2();
  void divide_by_2();

  /**
  ** type checking
  **/

  friend bool is_char(const bigint & a);
  friend bool is_uchar(const bigint & a);
  friend bool is_short(const bigint & a);
  friend bool is_ushort(const bigint & a);
  friend bool is_int(const bigint & a);
  friend bool is_uint(const bigint & a);
  friend bool is_long(const bigint & a);
  friend bool is_ulong(const bigint & a);

#endif

  /**
  ** assignments
  **/

  int operator = (int i);
  long operator = (long l);
  unsigned long operator = (unsigned long ul);
  double operator = (double d);
  bigint & operator = (const bigint & a);

  /**
  ** comparisons
  **/

  friend bool operator == (const bigint & a, const bigint & b);
  friend bool operator != (const bigint & a, const bigint & b);
  friend bool operator > (const bigint & a, const bigint & b);
  friend bool operator >= (const bigint & a, const bigint & b);
  friend bool operator < (const bigint & a, const bigint & b);
  friend bool operator <= (const bigint & a, const bigint & b);

  /**
  ** operator overloading
  **/

  friend bigint operator - (const bigint & a);
  friend bigint operator + (const bigint & a, const bigint & b);
  friend bigint operator - (const bigint & a, const bigint & b);
  friend bigint operator *(const bigint & a, const bigint & b);
  friend bigint operator / (const bigint & a, const bigint & b);
  friend bigint operator % (const bigint & a, const bigint & b);
  friend bigint operator << (const bigint & a, long u);
  friend bigint operator >> (const bigint & a, long u);
  friend bigint operator & (const bigint & a, const bigint & b);
  friend bigint operator | (const bigint & a, const bigint & b);
  friend bigint operator ^ (const bigint & a, const bigint & b);

  bigint & operator += (const bigint & a);
  bigint & operator -= (const bigint & a);
  bigint & operator *= (const bigint & a);
  bigint & operator /= (const bigint & a);
  bigint & operator %= (const bigint & a);
  bigint & operator <<= (long ui);
  bigint & operator >>= (long ui);
  bigint & operator &= (const bigint & a);
  bigint & operator |= (const bigint & a);
  bigint & operator ^= (const bigint & a);

  bigint operator~ () const;
  bigint & operator++ ();
  bigint & operator-- ();
  bigint   operator++ (int);
  bigint   operator-- (int);
  int operator ! () const;

#ifndef HEADBANGER

  /**
  ** Procedural versions
  **/

  friend void negate(bigint & a, const bigint & b);
  friend void add(bigint & c, const bigint & a, const bigint & b);
  friend void subtract(bigint & c, const bigint & a, const bigint & b);
  friend void multiply(bigint & c, const bigint & a, const bigint & b);
  friend void divide(bigint & c, const bigint & a, const bigint & b);
  friend void remainder(bigint & c, const bigint & a, const bigint & b);
  friend void div_rem(bigint & q, bigint & r, const bigint & a, const bigint & b);
  friend void shift_left(bigint & c, const bigint & a, long ui);
  friend void shift_right(bigint & c, const bigint & a, long ui);
  friend void power(bigint & c, const bigint & a, const bigint & b);
  friend void power(bigint & c, const bigint & a, long i);
  friend void and(bigint & c, const bigint & a, const bigint & b);
  friend void or(bigint & c, const bigint & a, const bigint & b);
  friend void xor(bigint & c, const bigint & a, const bigint & b);
  friend void not(bigint & c, const bigint & a);
  friend void inc(bigint & c);
  friend void dec(bigint & c);

  friend void add(bigint & c, const bigint & a, long i);
  friend void subtract(bigint & c, const bigint & a, long i);
  friend void multiply(bigint & c, const bigint & a, long i);
  friend void divide(bigint & c, const bigint & a, long i);
  friend void remainder(long &r, const bigint & a, long i);
  friend long remainder(const bigint & a, long i);
  friend void div_rem(bigint & q, long &r, const bigint & a, long i);
  friend void invert(bigint & a, const bigint & b);

#endif

  /**
  ** gcd's
  **/

  friend bigint gcd(const bigint & a, const bigint & b);
  friend bigint bgcd(const bigint & a, const bigint & b);
  friend bigint dgcd(const bigint & a, const bigint & b);
  friend bigint xgcd(bigint & u, bigint & v, const bigint & a, const bigint & b);
  friend bigint xgcd_left(bigint & u, const bigint & a, const bigint & b);
  friend bigint xgcd_right(bigint & v, const bigint & a, const bigint & b);

  /**
  ** functions
  **/

  friend bigint abs(const bigint & a);
  friend void seed(const bigint & a);
  friend bigint randomize(const bigint & a);
  friend double dbl(const bigint & a);
  friend xdouble xdbl(const bigint & a);

  friend void sqrt(bigint & a, const bigint & b);
  friend void square(bigint & a, const bigint & b);
  friend void swap(bigint & a, bigint & b);

  /**
  ** input / output
  **/

  friend istream & operator >> (istream & in, bigint & a);
  friend ostream & operator << (ostream & out, const bigint & a);

  friend int string_to_bigint(const char *s, bigint & a);
  friend int bigint_to_string(const bigint & a, char *s);

  /**
  ** using fread/fwrite
  **/

  void read_from_file(FILE * fp);
  void write_to_file(FILE * fp);

  /**
  ** using fscanf/fprintf
  **/

  void scan_from_file(FILE * fp);
  void print_to_file(FILE * fp);

};


#include <LiDIA/interface_lib.h>

#endif



