// ==========================================================================
// $Source: /var/lib/cvs/Givaro/src/kernel/rational/givrational.h,v $
// Copyright(c)'1994-2009 by The Givaro group
// This file is part of Givaro.
// Givaro is governed by the CeCILL-B license under French law
// and abiding by the rules of distribution of free software.
// see the COPYRIGHT file for more details.
// Authors: M. Samama, T. Gautier
// $Id: givrational.h,v 1.13 2011-02-02 16:23:56 briceboyer Exp $
// ==========================================================================
/*! @file givrational.h
 * @ingroup rational
 * @brief Rationals (and domain)
 * NO DOC.
 */
#ifndef __GIVARO_rational_H
#define __GIVARO_rational_H
// #define __GIVARO_GMPplusplus_rational_H

#include "givaro/givinteger.h"
#include "givaro/givmodule.h"
#include "givaro/ring-interface.h"

namespace Givaro {

// ----------------------------------- Functions Rational

class Rational ;
int compare(const Rational& a, const Rational& b) ;
int absCompare(const Rational& a, const Rational& b) ;
const Rational pow(const Rational &r, const int64_t l);
const Integer floor (const Rational &r) ;
const Integer ceil  (const Rational &r) ;
const Integer round (const Rational &r) ;
const Integer trunc (const Rational &r) ;
const Rational abs  (const Rational &r) ;
const Rational pow (const Rational& n, uint l);
const Rational pow (const Rational& n, uint64_t l);
uint64_t length (const Rational& r) ;
int sign   (const Rational& r) ;
int isZero (const Rational& r) ;
int isOne  (const Rational& r) ;
int isMOne  (const Rational& r) ;
int isInteger(const Rational& r);

template<class RatElement>
class QField;


//! Rationals. No doc.
class Rational {

public :
        // Cstor et dstor
    Rational(Neutral n = Neutral::zero) ;
    Rational(int32_t n) ;
    Rational(uint32_t n) ;
    Rational(int64_t n) ;
    Rational(uint64_t n) ;
    Rational(int64_t n, int64_t d ) ;
    Rational(uint64_t n, uint64_t d ) ;
    Rational(int32_t n, int32_t d ) ;
    Rational(uint32_t n, uint32_t d ) ;
    Rational(double x) ;
    Rational(const char* s) ;
    Rational(const Integer& n) ;
    Rational(const Integer& n, const Integer& d, int red = 1 ) ;
        // Rational number reconstruction
	/*! @brief Rational number reconstruction.
	 * \f$ num/den \equiv f \mod m\f$, with \f$|num|<k\f$ and \f$0 < |den| \leq f/kf\f$
	 * @bib
	 * - von zur Gathen & Gerhard <i>Modern Computer Algebra</i>, 5.10, Cambridge Univ. Press 1999]
	 */

    Rational(const Integer& f, const Integer& m, const Integer& k, bool recurs = false ) ;
    Rational(const Rational&) ;
        //~Rational();

        // Predefined cstes
    static const Rational zero ;
    static const Rational one ;
    static const Rational mOne ;

        // Logical and physical copies
    Rational& operator = (const Rational& );
    Rational& logcpy (const Rational& ) ;
    Rational& copy (const Rational& ) ;

//------------------Equalities and inequalities between rationals
    friend int compare(const Rational& a, const Rational& b) ;
    friend int absCompare(const Rational& a, const Rational& b) ;


//----------------Elementary arithmetic between Rational
    Rational operator + (const Rational& r) const ;
    Rational operator - (const Rational& r) const ;
    Rational operator - () const ;
    Rational operator + () const ;
    Rational operator * (const Rational& r) const ;
    Rational operator / (const Rational &r) const ;
    Rational& operator += (const Rational& r) ;
    Rational& operator -= (const Rational& r) ;
    Rational& operator *= (const Rational& r) ;
    Rational& operator /= (const Rational &r) ;

    Integer operator % (const Integer &r) const;

//-----------------------------------------Arithmetic functions
    friend const Rational pow(const Rational &r, const int64_t l);

//-----------------------------------------Miscellaneous
    friend const Integer floor (const Rational &r) ;
    friend const Integer ceil  (const Rational &r) ;
    friend const Integer round (const Rational &r) ;
    friend const Integer trunc (const Rational &r) ;

    inline friend const Rational abs  (const Rational &r) ;

    friend const Rational pow (const Rational& n, uint32_t l) {
        Rational r;
        r.num = ::Givaro::pow(n.num, l); r.den =  ::Givaro::pow(n.den, l);
        return r;
    }

    friend const Rational pow (const Rational& n, uint64_t l) {
        Rational r;
        r.num =  ::Givaro::pow(n.num, l); r.den =  ::Givaro::pow(n.den, l);
        return r;
    }

    const Integer nume() const ;
    const Integer deno() const ;
    inline friend uint64_t length (const Rational& r) ;
    inline friend int sign   (const Rational& r) ;
    inline friend int isZero (const Rational& r) ;
    inline friend int isOne  (const Rational& r) ;
    inline friend int isMOne  (const Rational& r) ;
    inline friend int isInteger(const Rational& r);

    std::ostream& print ( std::ostream& o ) const ;

    inline Rational reduce(const Rational& R) const ;

    static void SetReduce() ;
    static void SetNoReduce() ;

        // -- Cast operators
    operator short() const { return (short)(int) *this; }
    operator uint16_t() const { return (uint16_t) (uint32_t) *this; }
    operator uint8_t() const { return (uint8_t)(uint32_t) *this; }
    operator uint32_t() const { return (uint32_t) (this->num/this->den); }
    operator int() const  { return (int) (this->num/this->den); }
    operator signed char() const { return (signed char) (int) *this; }
    operator uint64_t() const { return (uint64_t) (this->num/this->den); }
    operator int64_t() const { return (int64_t) (this->num/this->den); }
    operator std::string() const { return std::string(this->num)+'/'+std::string(this->den); }
    operator float() const { return ((float)this->num)/((float)this->den); }
    operator double() const { return ((double)this->num)/((double)this->den); }

protected: // Internal Representation : num/den
    Integer num, den;

public:
    enum ReduceFlag { Reduce = 0x1, NoReduce = 0x0 } ;
protected:
    static ReduceFlag flags ;    // flags that indicates is reduction is done or not
        // by default = Reduce
    Rational& reduce() ;
        // -- module initialization
    static void Init(int* argc, char***argv);
    static void End();
    friend class GivModule;
    friend class QField<Rational>;
        // Rational number reconstruction
    bool ratrecon(const Integer& f, const Integer& m, const Integer& k, bool recurs = false ) ;

public:
        // - exportation of the module
    static GivModule Module;
        // -- Cstor for Zero and One to delay initialization after the main
    Rational( givNoInit );
}; // ----------------------------------- End of Class Rationalional

extern std::istream& operator>> (std::istream& in, Rational& r) ;
}


#include "givaro/givrational.inl"

namespace Givaro {

//! Rational Domain
template<>
class QField<Rational> : public FieldInterface<Rational> {
public:
    using Self_t = QField<Element>;
    typedef Rational Element;
    typedef Rational Rep;

        // -- Cstor
    QField() : one(1), mOne(-one), zero(0) {}
    template<class X> QField(const X& x) : one(1), mOne(-one),zero(0) {}

    int operator==( const QField<Element>& ) const { return 1;}
    int operator!=( const QField<Element>& ) const { return 0;}

        // -- Constants
    const Element one;
    const Element mOne;
    const Element zero;

    uint64_t characteristic() const { return 0U; }
    Integer& characteristic(Integer& p) const { return p=characteristic();}
    uint64_t cardinality() const { return 0U; }
    Integer& cardinality(Integer& p) const { return p=cardinality();}

        // -- assignement
    Rep& init( Rep& a ) const{ return a; }
    Rep& init( Rep& a, const Integer& n, const Integer& d) const{ return a=Rational(n,d); }
    template<class XXX> Rep& init(Rep& r, const XXX& x) const {
        return Caster<Rep,XXX>(r,x); 
    }
    template<class XXX> XXX& convert(XXX& x, const Rep& a) const {
        return Caster<XXX,Rep>(x,a);
    }

    Rep& assign( Rep& a, const Rep& b) const { return a = b ; }
        // -- integers operators
    Integer& get_num(Integer& n, const Element& r) const { return n=r.nume();}
    Integer& get_den(Integer& d, const Element& r) const { return d=r.deno();}

        // -- arithmetic operators
    Rep& mul( Rep& r, const Rep& a, const Rep& b ) const { return r = a * b; };
    Rep& div( Rep& r, const Rep& a, const Rep& b ) const { return r = a / b; };
    Rep& add( Rep& r, const Rep& a, const Rep& b ) const { return r = a + b; };
    Rep& sub( Rep& r, const Rep& a, const Rep& b ) const { return r = a - b; };

    Rep& mulin( Rep& r, const Rep& a) const { return r *= a; };
    Rep& divin( Rep& r, const Rep& a) const { return r /= a; };
    Rep& addin( Rep& r, const Rep& a) const { return r += a; };
    Rep& subin( Rep& r, const Rep& a) const { return r -= a; };

    Rep& axpy( Rep& r, const Rep& a, const Rep& b, const Rep& c ) const
        { return r = a * b + c; };
    Rep& axpyin( Rep& r, const Rep& a, const Rep& b ) const
        { return r += a * b; };
    Rep& maxpy( Rep& r, const Rep& a, const Rep& b, const Rep& c ) const
        { return r = c - a * b; };
    Rep& axmy( Rep& r, const Rep& a, const Rep& b, const Rep& c ) const
        { return r = a * b - c; };
    Rep& axmyin( Rep& r, const Rep& a, const Rep& b ) const
        { return r = a * b - r ; };
    Rep& maxpyin( Rep& r, const Rep& a, const Rep& b ) const
        { return r -= a * b; };

        // -- unary methods
    Rep& neg( Rep& r, const Rep& a ) const { return r = -a; };
    Rep& inv( Rep& r, const Rep& a ) const { r.num=a.den; r.den=a.num; return r; }
    Rep& negin( Rep& r ) const { r.num=-r.num; return r; }
    Rep& invin( Rep& r ) const { std::swap(r.num,r.den); return r; }

        // - return n^l
    Rep& pow(Rep& r, const Rep& n, const uint64_t l) const { return r =  ::Givaro::pow(n, l); }
    Rep& pow(Rep& r, const Rep& n, const uint32_t l) const { return r =  ::Givaro::pow(n, l); }


        // - Rational number reconstruction
    Rep& ratrecon(Rep& r, const Integer& f, const Integer& m, const Integer& k, bool recurs = false) const {
        return r = Rational(f,m,k,recurs);
    }
    Rep& ratrecon(Rep& r, const Integer& f, const Integer& m, bool recurs=true) const {
        return r = Rational(f,m, ::Givaro::sqrt(m),recurs);
    }


        // - Misc
    size_t length (const Rep& a) const { return  ::Givaro::length(a); }
    int sign    (const Rep& a) const { return  ::Givaro::sign(a); }
    bool isOne   (const Rep& a) const { return compare(a, one) ==0; }
    bool isMOne   (const Rep& a) const { return compare(a, mOne) ==0; }
    bool isUnit   (const Rep& a) const { return !isZero(a); }
    bool isZero  (const Rep& a) const { return compare(a, zero) ==0; }
    bool areEqual (const Rep& a, const Rep& b) const { return compare(a, b) ==0; }
    int areNEqual(const Rep& a, const Rep& b) const { return compare(a, b) !=0; }
    typedef GeneralRingRandIter<Self_t> RandIter;
    typedef GeneralRingNonZeroRandIter<Self_t> NonZeroRandIter;
    
    template< class MyRandIter > Rep& random(MyRandIter& g, Rep& r, int64_t s = 1) const { return r=Rational(Integer::random(s), Integer::nonzerorandom(s)); }
    template< class MyRandIter > Rep& random(MyRandIter& g, Rep& r, const Rep& b) const { Integer rnum,rden; Integer::random(rnum,b.nume()); Integer::nonzerorandom(rden,b.deno()); return r=Rational(rnum,rden); }
    template< class MyRandIter > Rep& nonzerorandom(MyRandIter& g, Rep& r, int64_t s = 1) const { return r=Rational(Integer::nonzerorandom(s), Integer::nonzerorandom(s)); }
    template< class MyRandIter > Rep& nonzerorandom (MyRandIter& g,Rep& r, const Rep& b) const { Integer rnum,rden; Integer::nonzerorandom(rnum,b.nume()); Integer::nonzerorandom(rden,b.deno()); return r=Rational(rnum,rden); }


        // -- IO
        // -- IO
    std::istream& read ( std::istream& i )
        { char ch;
        i >> std::ws >> ch;
        if (ch != 'R')
            GivError::throw_error(GivBadFormat("QField<Element>::read: bad signature domain"));
        return i;
        }
    std::ostream& write( std::ostream& o ) const { return o << 'R'; }
    std::istream& read ( std::istream& i, Rep& n) const { return i >> n; }
    std::ostream& write( std::ostream& o, const Rep& n) const { return n.print(o); }
};

} //namespace Givaro

#endif // __GIVARO_rational_H

// vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s:syntax=cpp.doxygen
