/*****************************************************************
  
  Fix.h
  
  Author: Fatih Ugurdag
  
  Basic Fixed point class.
  
*****************************************************************/

#define VERBOSE

#include <stdio.h>
#include <math.h>

template <int bitWidth, int integerWidth> class Fix
{
 protected:
  double value;
  double resolution;
  double upper_limit;
  double twice_upper_limit;
  char   *variable_name; 

 public:
  operator double() const { return value; }

  Fix (const double val = 0, char *vname = "variable") { 
    int decimalWidth = bitWidth -integerWidth -1;
    resolution = pow (2, -decimalWidth);
    upper_limit = pow (2, integerWidth);
    twice_upper_limit = 2 *upper_limit;
    variable_name = vname;

    *this = val;
  }

  double operator= (const double operand) {
    value = resolution *floor (operand /resolution);

#ifdef VERBOSE
    if (value >= upper_limit) {
      FILE *fp_overfl = fopen ("overflow.dat", "a");
      fprintf (fp_overfl, "%s: overflow: %f\n", variable_name, value);
      fclose (fp_overfl);
    } else if (value < -upper_limit) {
      FILE *fp_underfl = fopen ("underflow.dat", "a");
      fprintf (fp_underfl, "%s: underflow: %f\n", variable_name, value);
      fclose (fp_underfl);
    }
#endif

    this->over_under_flow ();

    return value;
  }

  double round_and_set (const double val) {
    *this = val +resolution/2;

    return value;
  }

  virtual double over_under_flow () {
    /* roll-over */
    value -= twice_upper_limit *floor (value /twice_upper_limit);
    if (value >= upper_limit) {
      value -= twice_upper_limit;
    }

    // cout << "roll-over\n";

    return value;
  }

  double operator+= (const double operand) {
    return (*this = value +operand);
  }

  double operator-= (const double operand) {
    return (*this = value -operand);
  }

  double operator*= (const double operand) {
    return (*this = value *operand);
  }

  double operator/= (const double operand) {
    return (*this = value /operand);
  }
};

template <int bitWidth, int integerWidth> class Fixs
  : public Fix <bitWidth,integerWidth>
{
 public:
  Fixs (double val=0, char *vname = "variable") : Fix <bitWidth,integerWidth> (val, vname) {	
    *this = val;
  }

  double operator= (const double operand) {
    Fix <bitWidth,integerWidth> &temp = *this;
    temp = operand;

    return this.value;
  }

  double over_under_flow () {
    /* saturation */
    if (this.value >= this.upper_limit) {
      this.value = this.upper_limit -this.resolution;
    } else if (this.value < -this.upper_limit) {
      this.value = -this.upper_limit;
    }

    // cout << "saturated\n";

    return this.value;
  }
};
