/*---------------------------------------------------------------------------*
 *                                   IT++			             *
 *---------------------------------------------------------------------------*
 * Copyright (c) 2004 by Johan Bergman.                                      *
 *                                                                           *
 * Permission to use, copy, modify, and distribute this software and its     *
 * documentation under the terms of the GNU General Public License is hereby *
 * granted. No representations are made about the suitability of this        *
 * software for any purpose. It is provided "as is" without expressed or     *
 * implied warranty. See the GNU General Public License for more details.    *
 *---------------------------------------------------------------------------*/

/*!
  \file
  \brief Fixed-point data type Fix
  \author Johan Bergman
  
  1.7
  
  2004/09/28 20:18:52
*/

#ifndef __fix_h
#define __fix_h

#include "base/fix_base.h"
#include "base/fix_factory.h"

namespace itpp {

  // Forward declarations
  template<class Num_T> class Vec;
  template<class Num_T> class Mat;

  //! \addtogroup fixtypes
  //!@{

  /*!
    \brief Fixed-point data type
  
    See the Detailed Description in the \ref fixtypes module.
  */
  class Fix : public Fix_Base {
    friend class CFix;
    template<int, e_mode, o_mode, q_mode> friend class Fixed;
    template<int, e_mode, o_mode, q_mode> friend class CFixed;
  public:
    //! Default constructor
    Fix(double x=0.0, int s=0, int w=MAX_WORDLEN, e_mode e=TC, o_mode o=WRAP, q_mode q=TRN, Stat *ptr=0)
      : Fix_Base(s, w, e, o, q, ptr), re(scale_and_apply_modes(x)) {}
    //! Constructor
    explicit Fix(const Fix_Factory &f)
      : Fix_Base(0, f.wordlen, f.emode, f.omode, f.qmode, f.stat_ptr), re(0) {}
    //! Constructor for internal use. No restrictions are applied. The dummies help to avoid ambiguities
    Fix(fixrep r, int s, int dummy1, int dummy2)
      : Fix_Base(s), re(r) {}
    //! Copy constructor
    Fix(const Fix &x, int w=MAX_WORDLEN, e_mode e=TC, o_mode o=WRAP, q_mode q=TRN, Stat *ptr=0)
      : Fix_Base(x.shift, w, e, o, q, ptr), re(x.re) {}
    //! Destructor
    virtual ~Fix() {}

    //! Assignment from Fix
    Fix& operator=(const Fix &x);
    //! Assignment from int
    Fix& operator=(const int x);
    //! Addition of Fix
    Fix& operator+=(const Fix &x);
    //! Addition of int
    Fix& operator+=(const int x);
    //! Subtraction of Fix
    Fix& operator-=(const Fix &x);
    //! Subtraction of int
    Fix& operator-=(const int x);
    //! Multiplication with Fix
    Fix& operator*=(const Fix &x);
    //! Multiplication with int
    Fix& operator*=(const int x);
    //! Division with Fix using quantization mode \c TRN
    Fix& operator/=(const Fix &x);
    //! Division with int using quantization mode \c TRN
    Fix& operator/=(const int x);
    //! Unary negative of Fix
    Fix operator-() const;
    //! Left shift \c n bits
    Fix& operator<<=(const int n);
    //! Right shift \c n bits using quantization mode \c qmode (constructor argument)
    Fix& operator>>=(const int n);

    //! Set to <tt>x * pow2(n)</tt> using quantization mode \c qmode (constructor argument)
    void set(double x, int n);
    //! Set to <tt>x * pow2(n)</tt> using quantization mode \c q (function argument)
    void set(double x, int n, q_mode q);
    //! Set data representation (mainly for internal use since it reveals the representation type)
    void set_re(fixrep x) {re = apply_o_mode(x);}

    //! Left shift \c n bits
    void lshift(int n);
    //! Right shift \c n bits using quantization mode \c qmode (constructor argument)
    void rshift(int n);
    //! Right shift \c n bits using quantization mode \c q (function argument)
    void rshift(int n, q_mode q);

    //! Print restrictions
    virtual void print() const;
    //! Get data representation (mainly for internal use since it reveals the representation type)
    fixrep get_re() const {return re;}
    //! Conversion to double
    double unfix() const;

#ifndef NO_IMPLICIT_FIX_CONVERSION
    //! Conversion to double
    operator double() const
    {
      it_assert1(shift>=-63 && shift<=64, "Fix::operator double: Illegal shift!");
      return double(re)*DOUBLE_POW2[64 - shift];
    }
#endif

    //! Check that x.shift==y.shift OR x==0 OR y==0 and return the shift (for the non-zero argument)
    friend int assert_shifts(const CFix &x, const Fix &y);
    //! Check that x.shift==y.shift OR x==0 OR y==0 and return the shift (for the non-zero argument)
    friend int assert_shifts(const Fix &x, const Fix &y);
    //! Check that x.shift==0 OR x==0 OR y==0 and return x.shift
    friend int assert_shifts(const Fix &x, int y);

  protected:
    //! Data representation
    fixrep re;
  };

  //! Input bit representation and, optionally, the shift
  std::istream &operator>>(std::istream &is, Fix &x);
  //! Output bit representation and, optionally, the shift
  std::ostream &operator<<(std::ostream &os, const Fix &x);

  //! Typedef for fixed-point vector type
  typedef Vec<Fix> fixvec;
  //! Typedef for fixed-point matrix type
  typedef Mat<Fix> fixmat;

  //!@}

} //namespace itpp

#endif // __fix_h


syntax highlighted by Code2HTML, v. 0.9.1