// ----------------------------------------------------------------------------
// --------------------- Functions for detect exceptions ----------------------
// ----------------------------------------------------------------------------
// detect exception in sc_float
public :
  bool is_zero()
   {
    return (exp == 0 && man == 0);
   }
  bool is_inf()
   {
    return (exp == ((1 << E_width)-1) && man == 0);    
   }
  bool is_NaN()
   {
    return (exp == ((1 << E_width)-1) && man != 0);     
   }
  bool is_denormal()
   {
     return (exp == 0 && man != 0);       
   }
  bool is_zero_or_denormal()
   {
     return (exp == 0);       
   }

private :
  bool is_zero(sc_float fp)
   {
    return (fp.exp == 0 && fp.man == 0);
   }

  bool is_zero(const sc_float fp) const
   {
    return (fp.exp == 0 && fp.man == 0);
   }

  bool is_inf(sc_float fp)
   {
    return (fp.exp == ((1 << E_width)-1) && fp.man == 0);    
   }

  bool is_inf(const sc_float fp) const
   {
    return (fp.exp == ((1 << E_width)-1) && fp.man == 0);    
   }

  bool is_NaN(sc_float fp)
   {
    return (fp.exp == ((1 << E_width)-1) && fp.man != 0);     
   }

  bool is_NaN(const sc_float fp) const
   {
    return (fp.exp == ((1 << E_width)-1) && fp.man != 0);     
   }

  bool is_denormal(sc_float fp)
   {
     return (fp.exp == 0 && fp.man != 0);       
   }

  bool is_denormal(const sc_float fp) const
   {
     return (fp.exp == 0 && fp.man != 0);       
   }

  bool is_zero_or_denormal(const sc_float fp) const
   {
     return (fp.exp == 0);       
   }

private:
// ----------------------------------------------------------------------------
// -------------------- Functions for float multiplication --------------------
// ----------------------------------------------------------------------------
#define c_DEBUG false
 sc_float multiply_exceptions (sc_float<E_width,M_width> mul1,sc_float<E_width,M_width> mul2)
  {
   sc_float<E_width,M_width> res;      // result

    // sign - XOR function
   res.sign = mul1.sign ^ mul2.sign;

   // 1. exceptions
   // if NaN - result is always NaN
   if (is_NaN(mul1) || is_NaN(mul2))
    {
     if (c_DEBUG)
      std::cout << "DEBUG: multiply : NaN appeared " << endl; //DEBUG
#ifndef COMB_ARITH 
   wait(2);
#endif
      res.exp = (1 << E_width)-1;
      res.man = 1;
    }
   // if zero - result is zero (only multiplied by inf -> NaN)
#ifdef EN_DENORM_NUM
   else if (is_zero(mul1) || is_zero(mul2)) 
#else
   else if (is_zero_or_denormal(mul1) || is_zero_or_denormal(mul2)) 
#endif
    {
     if (c_DEBUG)
      std::cout << "DEBUG: multiply : zero appeared " << endl; //DEBUG
#ifndef COMB_ARITH 
   wait(2);
#endif
     if (is_inf(mul1) || is_inf(mul2)) // result NaN
      {
       if (c_DEBUG)
        std::cout << "DEBUG: multiply : zero & inf appeared " << endl; //DEBUG
       res.exp = (1 << E_width)-1;
       res.man = 1;
      }
     else
      {
       res.exp = 0;
       res.man = 0;
      }
    }
   // if infinity - result is infinity (only multiplied by zero -> NaN)
   else if (is_inf(mul1) || is_inf(mul2))
    {
     if (c_DEBUG)
      std::cout << "DEBUG: multiply : inf appeared " << endl; //DEBUG
#ifndef COMB_ARITH 
   wait(2);
#endif
     if (is_inf(mul1) && is_inf(mul2)) // result NaN
      {
       res.exp = (1 << E_width)-1;
       res.man = 1;
      }
     else
      {
       res.exp = (1 << E_width)-1;
       res.man = 0;
      }
    }
   // multiply normal numbers
   else
    {
     res = multiply (mul1, mul2);
    } 
   return res;
  }

//#define c_DEBUG true
sc_float  multiply (sc_float mul1,sc_float mul2)     // TODO - mantisa underflow
  {
   sc_float                 res;      // result
#ifdef EN_DENORM_NUM // TODO - no conversion function between biguint a uint for barrel shifter 
   sc_uint < (M_width   + 2) > man1, man2;
   sc_uint < (2*M_width + 2) > man;
   unsigned int man_shift = 0;
#else
   sc_biguint < (M_width   + 2) > man1, man2;
   sc_biguint < (2*M_width + 2) > man;
#endif
   sc_uint    < (E_width   + 2) > exp;
   sc_uint    <   1       > exp1_inc = 0, exp2_inc = 0;

   res.sign = mul1.sign ^ mul2.sign;

   const unsigned c_TOP_BOUND = (M_width-1);
   const unsigned c_BOTTOM_BOUND = (int)((M_width-1)/2*(1.0-_SC_FLOAT_MULT_ACCURACY_));
   const unsigned c_LENGTH = c_TOP_BOUND - c_BOTTOM_BOUND + 1;
   const unsigned c_ROUNDING_BITS = c_BOTTOM_BOUND < 4 ? c_BOTTOM_BOUND : 4;
                                        // default number of rounding bits is 4

//   std::cout <<" DEBUG : c_TOP_BOUND = " << c_TOP_BOUND << endl;
//   std::cout <<" DEBUG : c_BOTTOM_BOUND = " << c_BOTTOM_BOUND << endl;
//   std::cout <<" DEBUG : c_LENGTH = " << c_LENGTH << endl;
//   std::cout <<" DEBUG : c_ROUNDING_BITS = " << c_ROUNDING_BITS << endl;

  // rounding & preprocessing (detect denormal, add 1 (hidden bit), rounding of input data)

   if (c_DEBUG)
    std::cout << "DEBUG: multiply : num1.man: " << mul1.man << ", num1.exp: " << mul1.exp << endl; //DEBUG
   if (c_DEBUG)
    std::cout << "DEBUG: multiply : num2.man: " << mul2.man << ", num2.exp: " << mul2.exp << endl; //DEBUG

   man1 = mul1.man.range(c_TOP_BOUND, c_BOTTOM_BOUND);
   man2 = mul2.man.range(c_TOP_BOUND, c_BOTTOM_BOUND);

#ifdef EN_DENORM_NUM
   if (!(is_denormal(mul1))) 
#endif
     man1[c_LENGTH] = 1;

#ifdef EN_DENORM_NUM
   if (!(is_denormal(mul2))) 
#endif
     man2[c_LENGTH] = 1;

  // rounding
   if ( c_ROUNDING_BITS > 1)
    {
     if (mul1.man[c_BOTTOM_BOUND - 1] && 
         (mul1.man.range((c_BOTTOM_BOUND - 2), (c_BOTTOM_BOUND - c_ROUNDING_BITS))
                                                      || mul1.man[c_BOTTOM_BOUND]))
       man1 += 1;
     if (mul2.man[c_BOTTOM_BOUND - 1] && 
         (mul2.man.range((c_BOTTOM_BOUND - 2), (c_BOTTOM_BOUND - c_ROUNDING_BITS))
                                                      || mul2.man[c_BOTTOM_BOUND]))
       man2 += 1;
    }

  // detect overflow
   if (man1[c_LENGTH + 1]) 
    {
     if (c_DEBUG)
      std::cout << "DEBUG: multiply : mantisa 1 overflows after rounding : man1 : "
                << man1 << endl; //DEBUG
     man1 = man1 >> 1;
     exp1_inc = 1;
    }
   if (man2[c_LENGTH + 1]) 
    {
     if (c_DEBUG)
      std::cout << "DEBUG: multiply : mantisa 2 overflows after rounding : man2 : "
                << man2 << endl; //DEBUG
     man2 = man2 >> 1;
     exp2_inc = 1;
    }
#ifndef COMB_ARITH 
   wait();
#endif
   if (c_DEBUG)
    std::cout << "DEBUG: multiply : man1 before mult: " << man1 << endl; //DEBUG
   if (c_DEBUG)
    std::cout << "DEBUG: multiply : man2 before mult: " << man2 << endl; //DEBUG
   if (c_DEBUG)
    std::cout << "DEBUG: multiply : exp  before mult: " << exp  << endl; //DEBUG

  // multiplication - exp addition, man multiplication
   exp = (mul1.exp + mul2.exp + exp1_inc + exp2_inc);
   man = man1.range(M_width,0) * man2.range(M_width,0);

#ifndef COMB_ARITH 
   wait();
#endif

   if (c_DEBUG)
    std::cout << "DEBUG: multiply : man after mult: " << man << endl; //DEBUG
   if (c_DEBUG)
    std::cout << "DEBUG: multiply : exp after mult: " << exp << endl; //DEBUG

  // exponent underflow
   if (exp < ((1 << (E_width-1)) - 1))
    {
#ifdef EN_DENORM_NUM 
     if (c_DEBUG)
      std::cout << "DEBUG: multiply : exponent underflows : data to barrel_shifter : man :"
                << man.range(2*c_LENGTH+1, c_LENGTH) << ", shift : "
                << ((1 << (E_width-1)) - 1 - exp) << endl; //DEBUG
     man = (man.range(2*c_LENGTH+1, c_LENGTH)) >> ((1 << (E_width-1)) - 1 - exp);
#else
     if (c_DEBUG)
      std::cout << "DEBUG: multiply : exponent underflows : exp : " << exp
                << ", man : " << man << endl; //DEBUG
     man = 0;
#endif
     exp = 0;
    }
   else
    {
     exp -= ((1 << (E_width-1)) - 1);

#ifdef EN_DENORM_NUM
    // mantisa underflow
     if(!(man[2*c_LENGTH] || man[2*c_LENGTH + 1]))
      {
       if(exp != 0)
        {
        // get bitshift value to normalize
         for (int i = M_width; i > 0; --i)
          {
           if (man[i] == 0)
            {
             man_shift++;
             if (c_DEBUG)
              std::cout << "DEBUG: multiply: underflow man : man["<< i << "] = "
                        << man[i] << " , man_shift = " << man_shift << endl; //DEBUG
            }
           else
            {
             break;
             if (c_DEBUG)
              std::cout << "DEBUG: multiply : underflow man : man["<< i << "] = "
                        << man[i] << " , break" << endl; //DEBUG
            }
          }
        // shift mantisa with barrel shifter
         if (exp == man_shift)
          // FIXME - something between normal and denormal 
          // -> result is the smallest normal number .. or should it be the biggest denormal ???
          {
           man = 0;
           exp = 1;
          }
         else
          {
           if (man_shift > exp) // result is denormal number
            {
             exp = 0;
            }
           else  // result is normal number
            {
             exp -= man_shift;
            }
             man = man.range(2*c_LENGTH+1, c_LENGTH) << man_shift;
           }
        }
    // else - no operation with mantisa - result is denormal number (or zero)
      }
#endif

    // overflow of mantisa -> get normalized value, shift mantisa to get correct number of bits of mantisa
     if (man[2*c_LENGTH + 1]) 
      {
       if (c_DEBUG)
        std::cout << "DEBUG: multiply : mantisa overflows : man : " << man << endl; //DEBUG
       if (man[2*c_LENGTH - M_width + 1] & man[2*c_LENGTH - M_width])
         man += 1 << (2*c_LENGTH - M_width + 1);     //rounding
       man = man >> (2*c_LENGTH - M_width + 1);
       exp += 1;
      }
     // shift mantisa to get correct number of bits of mantisa
     else
      {
       if (c_DEBUG)
        std::cout << "DEBUG: multiply : mantisa not overflows : man : " << man << endl; //DEBUG
       if (man[2*c_LENGTH - M_width] & man[2*c_LENGTH - M_width - 1])
         man += 1 << (2*c_LENGTH - M_width - 1);     //rounding
       man = man >> (2*c_LENGTH - M_width);
       if(man[M_width+1]) // if mantisa overflows after rounding
        {
       if (c_DEBUG)
        std::cout << "DEBUG: multiply : mantisa overflows after rounding: man : "
                  << man << endl; //DEBUG
         man = man >> 1;
         exp += 1;
        }
      }
     // overflow of exponent
     if (exp[E_width] || exp[E_width+1] || exp == ((1 << E_width) - 1))
      {
       exp = (1 << E_width) - 1;
       man = 0;
       if (c_DEBUG)
        std::cout << "DEBUG: multiply : exp overflow : man : " << man << endl; //DEBUG
       if (c_DEBUG)
        std::cout << "DEBUG: multiply : exp overflow : exp : " << exp << endl; //DEBUG
      }

     if (c_DEBUG)
      std::cout << "DEBUG: multiply : man after shift: " << man.range(M_width-1,0) << endl; //DEBUG
     if (c_DEBUG)
      std::cout << "DEBUG: multiply : exp after shift: " << exp << endl; //DEBUG
    }

   res.exp = exp;
   res.man = man.range(M_width-1,0);

   return res;
  }
#define c_DEBUG false


// ----------------------------------------------------------------------------
// --------------- Functions for float addition & subtraction -----------------
// ----------------------------------------------------------------------------
 sc_float add_sub_exceptions (sc_float add1, sc_float add2)
  {

   sc_float res;
 // 1. exceptions
   // if NaN - result is always NaN
   if (is_NaN(add1) || is_NaN(add2))
    {
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : NaN appeared " << endl; //DEBUG
     res.exp = (1 << E_width)-1;
     res.man = 1;
    }
   // if infinity - result is infinity
   else if (is_inf(add1) || is_inf(add2))
    {
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : inf appeared " << endl; //DEBUG
     // if both are infinity, result is NaN
     if (is_inf(add1) && is_inf(add2) && add1.sign != add2.sign)
      {
       res.exp = (1 << E_width)-1;
       res.man = 1;
      }
     else
      {
       res.exp = (1 << E_width)-1;
       res.man = 0;
       if (is_inf(add1))
        res.sign = add1.sign;
       else
        res.sign = add2.sign;
      }
    }
   // if add1 is zero
#ifdef EN_DENORM_NUM
   else if (is_zero(add1)) 
#else
   else if (is_zero_or_denormal(add1)) 
#endif
    {
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : zero appeared on sig1 " << endl; //DEBUG
#ifndef EN_DENORM_NUM
     if (is_zero_or_denormal(add2))
      {
       res.sign = add2.sign;
       res.exp  = 0;
       res.man  = 0;
      }
     else
#endif
      res = add2;
    }
   // if add2 is zero
#ifdef EN_DENORM_NUM
   else if (is_zero(add2)) 
#else
   else if (is_zero_or_denormal(add2)) 
#endif
    {
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : zero appeared on sig2" << endl; //DEBUG
#ifndef EN_DENORM_NUM
     if (is_zero_or_denormal(add1))
      {
       res.sign = add2.sign;
       res.exp  = 0;
       res.man  = 0;
      }
     else
#endif
      res = add1;
    }
   else
    {
     res = add_sub (add1, add2);
    }

   return res;
  }

//#define c_DEBUG true
 sc_float add_sub (sc_float num1, sc_float num2)
  {
   // define bit size according to rewuired accuracy
   const unsigned c_MSB_BIT = M_width * (_SC_FLOAT_ADD_SUB_ACCURACY_ + 1); // hidden bit
   const unsigned c_LSB_BIT = c_MSB_BIT - M_width;                         // last valid bit
   //const unsigned c_ROUNDING_BITS = c_BOTTOM_BOUND < 4 ? c_BOTTOM_BOUND : 4;

   sc_float res;
   sc_biguint<c_MSB_BIT + 1> man1, man2;
   sc_biguint<c_MSB_BIT + 1> adder_inp, adder_inn;
   sc_biguint<c_MSB_BIT + 3> man;
   sc_uint<E_width> exp;

   unsigned int exp_diff, man_shift = 0;
   bool exp2_bigger, man1_bigger;

   if (c_DEBUG)
    std::cout << "DEBUG: add_sub : num1.man : " << num1.man << endl; //DEBUG
   if (c_DEBUG)
    std::cout << "DEBUG: add_sub : num2.man : " << num2.man << endl; //DEBUG

   man1.range(c_MSB_BIT - 1, c_LSB_BIT) = num1.man;
   man2.range(c_MSB_BIT - 1, c_LSB_BIT) = num2.man;

#ifdef EN_DENORM_NUM
   if (!(is_denormal(num1)))
#endif
   man1[c_MSB_BIT] = 1;
#ifdef EN_DENORM_NUM
   if (!(is_denormal(num2)))
#endif
   man2[c_MSB_BIT] = 1;

   if (c_DEBUG)
    std::cout << "DEBUG: add_sub : man1 : " << man1 << ", valid bits: "
              << man1.range(c_MSB_BIT - 1, c_LSB_BIT) << endl; //DEBUG
   if (c_DEBUG)
    std::cout << "DEBUG: add_sub : man2 : " << man2 << ", valid bits: "
              << man2.range(c_MSB_BIT - 1, c_LSB_BIT) << endl; //DEBUG

   // operations with exponent - compare which is bigger, get difference
   exp2_bigger = (num2.exp> num1.exp);
   exp = exp2_bigger ? num2.exp : num1.exp;
   exp_diff = exp2_bigger ? (num2.exp - num1.exp) : (num1.exp - num2.exp);

   if (c_DEBUG)
    std::cout << "DEBUG: add_sub : compare exp1 : " << num1.exp << endl; //DEBUG
   if (c_DEBUG)
    std::cout << "DEBUG: add_sub : compare exp2 : " << num2.exp << endl; //DEBUG

   // if one of numbers is too small, result is the second number
   if (exp_diff > c_MSB_BIT)
     res = exp2_bigger ? num2 : num1;
   else
    {
   // operations with mantisa - shift mantisa according exponent difference
     if(exp2_bigger)
      {
       man1 = man1 >> exp_diff;
/*       if  (num1.man[c_MSB - exp_diff] && 
           (mul1.man.range((c_MSB - exp_diff), (c_MSB - exp_diff - c_ROUNDING_BITS))
                                                      || mul1.man[c_MSB - exp_diff+1]))
        man1 += 1;*/
      }
     else
      man2 = man2 >> exp_diff;
   // TODO - implement rounding ????
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : shift if bigger man1 : " << man1 << endl; //DEBUG
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : shift if bigger man2 : " << man2 << endl; //DEBUG

#ifndef COMB_ARITH 
   wait();
#endif

   // swap mantisas - the bigger one must go into positive input - to avoid negative result
     man1_bigger = (man1 > man2);
     adder_inp = man1_bigger ? man1 : man2;  
     adder_inn = man1_bigger ? man2 : man1; 

     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : switch sig1 : " << adder_inp << endl; //DEBUG
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : switch sig2 : " << adder_inn << endl; //DEBUG

   // add or subtract mantisas - according to sign of input numbers
     if (num1.sign == num2.sign)
      man = adder_inp + adder_inn;
     else
      man = adder_inp - adder_inn;
   
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : result man : " << man << endl; //DEBUG

#ifndef COMB_ARITH 
   wait();
#endif

   // if mantisa is zero
     if (man == 0)
      exp = 0;
     else
      {
   // if mantisa overflows
       if (man[c_MSB_BIT + 1])
        {
         if (c_DEBUG)
          std::cout << "DEBUG: add_sub : man overflow : man : " << man << endl; //DEBUG
         if (c_DEBUG)
          std::cout << "DEBUG: add_sub : man overflow : exp : " << exp << endl; //DEBUG

         if (man[c_LSB_BIT] & man[c_LSB_BIT + 1])
           man += 1;     //rounding
         man_shift = 1;
         if(man[c_MSB_BIT+2]) // if mantisa overflows after rounding
          {
           man_shift = 2;
          }
         man = man.range(c_MSB_BIT+1, 0) >> man_shift;
         exp += man_shift;
         if (c_DEBUG)
          std::cout << "DEBUG: add_sub : man overflow : shifted man : " << man << endl; //DEBUG
         if (c_DEBUG)
          std::cout << "DEBUG: add_sub : man overflow : exp after shift : " << exp << endl; //DEBUG
        }
   // if mantisa underflows
       else if (man[c_MSB_BIT] == 0)
        {
         if (c_DEBUG)
          std::cout << "DEBUG: add_sub : underflow man : " << man << endl; //DEBUG
         if (c_DEBUG)
          std::cout << "DEBUG: add_sub : underflow exp : " << exp << endl; //DEBUG
         for (int i = c_MSB_BIT; i > 0; --i)
          {
           if (man[i] == 0)
            {
             man_shift++;
             if (c_DEBUG)
              std::cout << "DEBUG: add_sub : underflow man : man["<< i << "] = "
                        << man[i] << " , man_shift = " << man_shift << endl; //DEBUG
            }
           else
            {
             if (c_DEBUG)
              std::cout << "DEBUG: add_sub : underflow man : man["<< i << "] = "
                        << man[i] << " , break" << endl; //DEBUG
             break;
            }
          }  //end for
#ifndef EN_DENORM_NUM
        //if exponent is big enough, normalize
         if (man_shift < exp)
          {
           man = man.range(c_MSB_BIT, 0) << man_shift;
           exp -= man_shift;
          }
         else
          {
           man = 0;
           exp = 0;
          }
        } // end if mantisa underflow
#else   // denormal numbers enabled
         if (exp == man_shift)
          // FIXME - something between normal and denormal 
          // -> result is the smallest normal number 
          //    .. or should it be the biggest denormal ???
          {
           man = 0;
           exp = 1;
          }
         else
          {
           if (man_shift > exp)  // result is denormal number
            {
             exp = 0;
            }
           else                 // result is normal number
            {
             exp -= man_shift;
            }
             man = man.range(c_MSB_BIT, 0) << man_shift;
           }
        } // end if mantisa underflow
       else if (exp == 0)  
          // FIXME - something between normal and denormal 
          // -> result of adding two denormal numbers but mantisa is normalizeded
          // -> make the smallest normal number
        {
         man = 0;
         exp = 1;
        }
#endif
      } //end if mantisa is zero
   // output assignment
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : output assignment : man : "
                << man.range(c_MSB_BIT-1,c_LSB_BIT) << ", from number : " << man << endl; //DEBUG
     if (c_DEBUG)
      std::cout << "DEBUG: add_sub : output assignment : exp : " << exp << endl; //DEBUG
     res.sign = (num1.sign == num2.sign) ? num1.sign : (man1_bigger ? num1.sign : num2.sign);
     res.exp = exp;
     res.man = man.range(c_MSB_BIT-1,c_LSB_BIT);
    }
   return res;
  }

#define c_DEBUG false
// ----------------------------------------------------------------------------
// ----------------------- Functions for float division -----------------------
// ----------------------------------------------------------------------------

 sc_float divide_exceptions(sc_float div1,sc_float div2)
  {
   sc_float res;      // result

    // sign - XOR function
   res.sign = div1.sign ^ div2.sign;

   // 1. exceptions
   // if NaN - result is always NaN
   if (is_NaN(div1) || is_NaN(div2))
    {
      res.exp = (1 << E_width)-1;
      res.man = 1;
    }
   // if zero - result is inf (only dividing inf -> NaN)
#ifndef EN_DENORM
   else if (is_zero(div2)) 
    {
     if (is_zero(div1) || is_inf(div1))  // result NaN
#else
   else if (is_zero_or_denormal(div2)) 
    {
     if (is_zero_or_denormal(div1) || is_inf(div1))  // result NaN 
#endif
      {
       res.exp = (1 << E_width)-1;
       res.man = 1;
      }
     else  // result inf
      {
       res.exp = (1 << E_width)-1;
       res.man = 0;
      }
    }
#ifdef EN_DENORM
   else if(is_zero(div1))
#else
   else if(is_zero_or_denormal(div1))
#endif
    {
     if (is_inf(div2))
      {
       res.exp = (1 << E_width)-1;
       res.man = 1;
      }
     else
      {
       res.exp = 0;
       res.man = 0;
      }
    }
   // if infinity - result is infinity (only inf/inf -> NaN)
   else if (is_inf(div2))
    {
     if (is_inf(div1))
      {
       res.exp = (1 << E_width)-1;
       res.man = 1;
      }
     else
      {
       res.exp = 0,
       res.man = 0;
      }
    }
   else if (is_inf(div1))
    {
     res.exp = (1 << E_width)-1;
     res.man = 0;
    }
   // if normal numbers
   else
    {
     res = divide (div1, div2);
    } 
   return res;
  }

//#define c_DEBUG true
sc_float  divide (sc_float div1,sc_float div2)     // TODO denormal not implemented
  {
   sc_float              res;      // result
   sc_uint < (M_width   + 1) > man, man2;
   sc_uint < (M_width   + 2) > man1;
   sc_uint < (E_width   + 1) > exp;
   
   res.sign = div1.sign ^ div2.sign;

//   std::cout <<" DEBUG : c_DVND_LENGTH = " << c_DVND_LENGTH << endl;
//   std::cout <<" DEBUG : c_DVDR_LENGTH = " << c_DVDR_LENGTH << endl;

   // exponent computation & detect exponent underflow, overflow

   // detect exponent underflow
   if ((div1.exp + ((1 << (E_width-1)) - 1)) < div2.exp)
    {
     exp = 0;
     man = 0;
    }
   else
    {
     exp = (div1.exp +  ((1 << (E_width-1)) - 1)) - div2.exp;
   // detect exponent overflow
     if (exp[E_width])
      {
       exp = (1 << E_width) - 1;
       man = 0;
      }
     // mantisa computation & detect denormal, add 1 (hidden bit)
     else
      {
       if (c_DEBUG) std::cout << "DEBUG: div_normal : num1.man: " << div1.man << endl; //DEBUG
       if (c_DEBUG) std::cout << "DEBUG: div_normal : num2.man: " << div2.man << endl; //DEBUG

       man1 = div1.man; // << (c_DVND_LENGTH - M_width - 1);
       man1[M_width] = 1;

       man2 = div2.man;
       man2[M_width] = 1;

       if (c_DEBUG) std::cout << "DEBUG: div_normal : man1 before div: " << man1 << endl; //DEBUG
       if (c_DEBUG) std::cout << "DEBUG: div_normal : man2 before div: " << man2 << endl; //DEBUG
       if (c_DEBUG) std::cout << "DEBUG: div_normal : exp  before div: " << exp << endl; //DEBUG

      // man = man1 / man2;

      // TODO implement denormal numbers

      // If the divisor can be subtracted from this part of the dividend, then
      // the corresponding bit of the quotient has to be 1, otherwise 0.
       for (int i = M_width+1; i> (int)(M_width*0.5*(1.0 - _SC_FLOAT_DIV_ACCURACY_)) ; --i)
        {
         if (man1 >= man2)
          {
           if (c_DEBUG)
            std::cout << "DEBUG: div_normal : man1>= man2 : run : " << i << " man1 : "
                      << man1  << ", man2 : " << man2 << endl; //DEBUG
           man1 -= man2;
           if (c_DEBUG)
            std::cout << "DEBUG: div_normal : man1>= man2 : run : " << i << " man1 "
                      << "after sub : " << man1 << endl; //DEBUG
           man[i-1] = 1;
           if (c_DEBUG)
            std::cout << "DEBUG: div_normal : man1>= man2 : run : " << i << " man : "
                      << man << endl; //DEBUG
          }
         man1 = man1 << 1;
         if (c_DEBUG)
          std::cout << "DEBUG: div_normal : end of cycle : run : " << i << " man1 : "
                    << man1 << ", man : "<< man << endl; //DEBUG
        }

       // normalize - if man1 < man2
       if (man[M_width] == 0)
        {
         if (c_DEBUG)
          std::cout << "DEBUG : div_normal : mantisa underflows " << endl;
         man = man << 1;
         exp -= 1;
        }
       if (exp == ((1 << E_width) - 1))
        {
         exp = (1 << E_width) - 1;
         man = 0;
        }
       if (c_DEBUG)
        std::cout << "DEBUG: div_normal : man after div: " << man << endl; //DEBUG
       if (c_DEBUG)
        std::cout << "DEBUG: div_normal : exp after div: " << exp << endl; //DEBUG

      }
    }

   res.exp = exp;
   res.man = man;

   return res;
  }
#define c_DEBUG false
//#define c_DEBUG true

 template <int sc_int_size>  sc_float<E_width,M_width> int2sc_float (sc_int <sc_int_size> num)
  {
   sc_float<E_width,M_width> fl;
   sc_uint <sc_int_size> unum;

   if (c_DEBUG)
    std::cout << "DEBUG: int2sc_float (sc_int) : input integer : " << num
              << ", bit width : " << sc_int_size << endl;

   if (num == 0)
    {
     fl.sign = false;
     fl.exp = 0;
     fl.man = 0;
    }
   else
    {
     if (num[sc_int_size-1])
      {
       fl.sign = true;
       unum =  0 - num;
      }
     else
      {
       fl.sign = false;
       unum = num;
      }

     if (c_DEBUG)
      std::cout << "DEBUG: int2sc_float (sc_int) : after sign resolution : "
                << unum << endl;

     for (int i = sc_int_size; i > 0; --i)
      {
       if (unum[sc_int_size -1] == 0)
        {
         unum = unum << 1;
//        if (c_DEBUG)
//         std::cout << "DEBUG: int2sc_float (sc_int) : searching leading one : run : "
//                   << i << ", unum: "<< unum << ", unum bit : " << unum[sc_int_size -1] << endl; //DEBUG
        }
       else // leading one found
        {
        // assign exponent
         fl.exp = (i - 1) + ((1 << (E_width-1)) - 1);  // position of MSB 1 + offset 

        // assign mantisa
         // integer is wider than mantisa
         if ((sc_int_size-1) > M_width) // TODO - rounding
          {
           fl.man = unum.range(sc_int_size-2, sc_int_size-1-M_width);  //throw away MSB - hidden bit in mantisa
           if (c_DEBUG)
             std::cout << "DEBUG: int2sc_float (sc_int) : highest one found : run : "
                       << i <<  ", and result is : " << fl.exp << ", " << fl.man
                       << ", " << fl << ", " << unum  << ", "
                       << unum.range(sc_int_size-2, sc_int_size-1-M_width) << endl;
          }  
         // integer is not wider than mantisa
         else
          {
           fl.man.range(M_width-1, M_width-sc_int_size+1) = unum.range(sc_int_size-2, 0);  //throw away MSB - hidden bit in mantisa
           if (c_DEBUG)
             std::cout << "DEBUG: int2sc_float (sc_int) : highest one found : run : "
                       << i <<  ", and result is : " << fl.exp << ", " << fl.man
                       << ", " << fl << ", " << unum  << ", "
                       << unum.range(sc_int_size-2, 0) << endl;
          }

         break;
        }
      }
    }
   return fl;
  }

#define c_DEBUG false
// function for conversion sc_uint to sc_float

 template <int sc_uint_size>  sc_float<E_width,M_width> uint2sc_float (sc_uint <sc_uint_size> unum)
  {
   sc_float<E_width,M_width> fl;

   if (c_DEBUG)
    std::cout << "DEBUG: int2sc_float (sc_uint) : input integer : "
              << unum << ", bit width : " << sc_uint_size << endl;

   fl.sign = false;

   if (unum == 0)
    {
     fl.exp = 0;
     fl.man = 0;
    }
   else
    {
     if (c_DEBUG)
      std::cout << "DEBUG: int2sc_float (sc_uint) : after sign resolution : " << unum << endl;
     for (int i = sc_uint_size; i > 0; --i)
      {
       if (unum[sc_uint_size -1] == 0)
        {
         unum = unum << 1;
     //    if (c_DEBUG)
     //     std::cout << "DEBUG: int2sc_float (sc_int) : searching leading one : run : "
     //               << i << endl; //DEBUG
        }
       else // highest one found
        {
         fl.exp = (i - 1) + ((1 << (E_width-1)) - 1);  // position of MSB 1 + offset 
         if ((sc_uint_size-1) > M_width) // rounding - floor 
          {
           fl.man = unum.range(sc_uint_size-2, sc_uint_size-1-M_width);  //throw away MSB - hidden bit in mantisa
           if (c_DEBUG)
            std::cout << "DEBUG: int2sc_float (sc_uint) : leading one found : run : "
                      << i <<  ", and result is : " << fl.exp << ", " << fl.man
                      << ", " << fl << ", " << unum  << ", " 
                      << unum.range(sc_uint_size-2, sc_uint_size-1-M_width) << endl;
          }
         else
          {
           fl.man.range(M_width-1, M_width-sc_uint_size+1) = unum.range(sc_uint_size-2, 0); //throw away MSB - hidden bit in mantisa
           if (c_DEBUG)
            std::cout << "DEBUG: int2sc_float (sc_uint) : leading one found : run : "
                      << i <<  ", and result is : " << fl.exp << ", " << fl.man
                      << ", " << fl << ", " << unum  << ", " 
                      << unum.range(sc_uint_size-2, 0) << endl;
          }
         break;
        }
      }
    }
   return fl;
  }

#define c_DEBUG false

