


//
// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : bigmod.h 
//		 (Most of the code was taken from the old 
//		  LiDIA - version of bigmod written by Thomas Papanikolaou.)
// Author      : Markus Maurer (MM)
// Last change : MM, Oct 18 1995, initial version 
//


#ifndef LIDIA_GLOBAL_BIGMOD_H
#define LIDIA_GLOBAL_BIGMOD_H  


#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:base_bigmod.h>
#include <LiDIA:multi_bigmod.h>
#else
#include <LiDIA/base_bigmod.h>
#include <LiDIA/multi_bigmod.h>
#endif


 class bigmod : public base_bigmod
  {

    //
    // ***** Friends of bigmod. *****
    // (The friend functions are implemented in multi_bigmod.c)
    //

    friend class multi_bigmod;

    friend void add (multi_bigmod&,const multi_bigmod&,const bigmod&);
    friend void add (multi_bigmod&,const bigmod&,const multi_bigmod&);
    friend void subtract (multi_bigmod&,const multi_bigmod&,const bigmod&);
    friend void subtract (multi_bigmod&,const bigmod&,const multi_bigmod&);
    friend void multiply (multi_bigmod&,const multi_bigmod&,const bigmod&);
    friend void multiply (multi_bigmod&,const bigmod&,const multi_bigmod&);
    friend void divide (multi_bigmod&,const multi_bigmod&,const bigmod&);
    friend void divide (multi_bigmod&,const bigmod&,const multi_bigmod&);

    friend bool operator == ( const multi_bigmod & a, const bigmod & b );
    friend bool operator == ( const bigmod & a, const multi_bigmod & b );
    friend bool operator != ( const multi_bigmod & a, const bigmod & b );
    friend bool operator != ( const bigmod & a, const multi_bigmod & b );
  
    private :

#ifndef HEADBANGER
	static residue_class <bigint> *Mp ;
#endif
	static bigint M ; 

    public :

        //
	// ***** modulus handling *****
	//

	static void set_modulus ( const bigint & m ) ;

	static const bigint & modulus ()
	 {return bigmod::M;}


        //
	// ***** constructors / destructor
	//

	bigmod ()
	 {}

	bigmod ( int i )
	 {I.assign(i); this->normalize();}

	bigmod ( long l )
	 {I = l; this->normalize();}

	bigmod ( unsigned long ul )
	 {I = ul; this->normalize();}

	bigmod ( double d )
	 {I = d; this->normalize();}

	bigmod ( const bigint & i )
	 {I.assign(i); this->normalize();}

	bigmod ( const bigmod & a )
	 {I.assign(a.I); this->normalize();}

        ~bigmod ()
	 {}

#ifndef HEADBANGER

        //
        // ***** inline member functions *****
        //

        bigint invert ( int i = 0 )
         {return base_bigmod::invert(bigmod::M,i);}

        void negate ()
         {base_bigmod::negate(bigmod::M);}

	void normalize ()
	 {base_bigmod::normalize(bigmod::M);}

        //
        // ***** assignments *****
        //

        void assign_zero ()
         {I.assign_zero();}

        void assign_one ()
         {I.assign_one();}

        void assign (int i)
         {I.assign (i); this->normalize();}

        void assign (long i)
         {I.assign (i); this->normalize();}

        void assign (unsigned long i)
         {I.assign (i); this->normalize();}

        void assign (const bigint & a)
         {I.assign (a); this->normalize();}

        void assign (const bigmod & a)
         {I.assign(a.I);}



        //
	// ***** member functions *****
	//

	void multiply_by_2 ()
	 {base_bigmod::multiply_by_2(bigmod::M);}

	void divide_by_2 ()
	 {base_bigmod::divide_by_2(bigmod::M);}

        void randomize ();

#endif

	//
	// ***** assignments *****
	//

	int operator = ( int i )
	 {I.assign(i); this->normalize(); return i;}

	long operator = ( long l )
         {I = l; this->normalize(); return l;}

	unsigned long operator = ( unsigned long ul )
         {I = ul; this->normalize(); return ul;}

	double operator = ( double d )
	 {I = d; this->normalize(); return d;}

	bigint operator = ( const bigint & a )
	 {I.assign(a); this->normalize(); return a;}

	const bigmod & operator = ( const bigmod & a )
	 {I.assign(a.I); return *this;}


        //
	// ***** comparisons *****
	//

	friend bool operator == ( const bigmod & a, const bigmod & b )
	 { if (a.I.compare(b.I) == 0) return true; else return false;}

	friend bool operator != ( const bigmod & a, const bigmod & b )
	 {if (a.I.compare(b.I) != 0) return true; else return false;}

  
        //
	// ***** operator overloading *****
	//

	friend bigmod operator - ( const bigmod & a ) ;

        friend bigmod operator + ( const bigmod & a, const bigmod & b )
	 {bigmod c; add(c, a, b); return c;}

        friend bigmod operator - ( const bigmod & a, const bigmod & b )
	 {bigmod c; subtract(c, a, b); return c;}

	friend bigmod operator * ( const bigmod & a, const bigmod & b )
	 {bigmod c; multiply(c, a, b); return c;}

	friend bigmod operator / ( const bigmod & a, const bigmod & b )
	 {bigmod c; divide(c, a, b); return c;}


	const bigmod & operator += ( const bigmod & a )
	 {add(*this, *this, a); return *this;}

	const bigmod & operator -= ( const bigmod & a )
	 {subtract(*this, *this, a); return *this;}

	const bigmod & operator *= ( const bigmod & a )
	 {multiply(*this, *this, a); return *this;}

	const bigmod & operator /= ( const bigmod & a )
	 {divide(*this, *this, a); return *this;}


	const bigmod & operator ++ ()
	 {inc(*this); return *this;}

	const bigmod & operator -- ()
	 {dec(*this); return *this;}

	int operator ! ()
	 {return I.is_zero();}


#ifndef HEADBANGER

        //
        // ***** arithmetical procedures *****
	//

	friend void invert ( bigmod & a, const bigmod & b )
	 {a.assign(b); a.invert();}

        friend void negate ( bigmod & a, const bigmod & b )
	 {a.assign(b);a.negate();}


	friend void add ( bigmod & c, const bigmod & a, const bigmod & b )
	 {add(c,a,b,bigmod::M);}

	friend void add ( bigmod & c, const bigint & a, const bigmod & b )
	 {add(c,a,b,bigmod::M);}

	friend void add ( bigmod & c, const bigmod & a, const bigint & b )
	 {add(c,a,b,bigmod::M);}

	friend void add ( bigmod & c, long a, const bigmod & b )
	 {add(c,a,b,bigmod::M);}

	friend void add ( bigmod & c, const bigmod & a, long b )
	 {add(c,a,b,bigmod::M);}



	friend void subtract ( bigmod & c, const bigmod & a, const bigmod & b )
	 {subtract(c,a,b,bigmod::M);}

	friend void subtract ( bigmod & c, const bigint & a, const bigmod & b )
	 {subtract(c,a,b,bigmod::M);}

	friend void subtract ( bigmod & c, const bigmod & a, const bigint & b )
	 {subtract(c,a,b,bigmod::M);}

	friend void subtract ( bigmod & c, long a, const bigmod & b )
	 {subtract(c,a,b,bigmod::M);}

	friend void subtract ( bigmod & c, const bigmod & a, long b )
	 {subtract(c,a,b,bigmod::M);}



	friend void multiply ( bigmod & c, const bigmod & a, const bigmod & b )
	 {multiply(c,a,b,bigmod::M);}

	friend void multiply ( bigmod & c, const bigint & a, const bigmod & b )
	 {multiply(c,a,b,bigmod::M);}

	friend void multiply ( bigmod & c, const bigmod & a, const bigint & b )
	 {multiply(c,a,b,bigmod::M);}

	friend void multiply ( bigmod & c, long a, const bigmod & b )
	 {multiply(c,a,b,bigmod::M);}

	friend void multiply ( bigmod & c, const bigmod & a, long b )
	 {multiply(c,a,b,bigmod::M);}



	friend void divide ( bigmod & c, const bigmod & a, const bigmod & b )
	 {divide(c,a,b,bigmod::M);}

	friend void divide ( bigmod & c, const bigint & a, const bigmod & b )
	 {divide(c,a,b,bigmod::M);}

	friend void divide ( bigmod & c, const bigmod & a, const bigint & b )
	 {divide(c,a,b,bigmod::M);}

	friend void divide ( bigmod & c, long a, const bigmod & b )
	 {divide(c,a,b,bigmod::M);}

	friend void divide ( bigmod & c, const bigmod & a, long b )
	 {divide(c,a,b,bigmod::M);}



	friend void power ( bigmod & c, const bigmod & a, const bigint & b )
	 {power(c,a,b,bigmod::M);}

	friend void power ( bigmod & c, const bigmod & a, long b )
	 {power(c,a,b,bigmod::M);}



	friend void inc ( bigmod & c )
	 {inc(c,bigmod::M);}

	friend void dec ( bigmod & c )
	 {dec(c,bigmod::M);}

#endif

        //
	// ***** functions *****
	//

	friend bigmod inverse ( const bigmod & a )
	 {bigmod c; c.assign(a); c.invert(); return c;}

	friend bigmod randomize ( const bigmod & a )
	 {bigmod c; c.I.assign(::randomize(a.I)); return c;}

#ifndef HEADBANGER
	friend bigmod randomize ();
#endif

	friend void normalize ( bigmod & a, const bigmod & b )
	 {bigint q, r; div_rem(q, r, b.I, bigmod::M); a.I.assign(r);}

	friend void square ( bigmod & a, const bigmod & b )
	 {square(a.I, b.I); remainder(a.I, a.I, bigmod::M);}

	friend void swap ( bigmod & a, bigmod & b )
	 {swap(b.I, a.I);}


	//
	// ***** input / output *****
	//

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

	friend int string_to_bigmod ( char * s, bigmod & a ) ;
	friend int bigmod_to_string ( const bigmod & a, char * s ) ;

	void read_from_file ( FILE * fp ) ;
	void write_to_file  ( FILE * fp ) ;
	void scan_from_file ( FILE * fp ) ;
	void print_to_file  ( FILE * fp ) ;
  } ;



#endif
