 /*
##########################################################################
#                                                                        #
# Program: IeeeCC754                                                     #
#                                                                        #
# Description:                                                           #
#   IeeeCC754 or IEEE 754 Compliance Checker is a precision and range    #
#   independent tool to test whether an implementation of                #
#   floating-point arithmetic (in hardware or software) is compliant     #
#   with the principles of the IEEE 754-854 floating-point standards.    #
#   You can find out more about the testing tool IeeeCC754 at            #
#                                                                        #
#         http://www.win.ua.ac.be/~cant/ieeecc754.html                   #
#                                                                        #
#   This tool is in parts based on and greatly benefited from the        #
#   the program FPTEST developed by Jerome Coonen. For a full            #
#   description of the extensions to FPTEST and a reference to           #
#   the original Coonen program, please refer to the URL given above.    #
#   For the options available with the program IeeeCC754 and its         #
#   compatibility with David Hough's hexadecimal UCB format, we          #
#   also refer to the file readme.usage.                                 #
#                                                                        #
#  Usage: see readme.usage                                               #
#                                                                        #
#  Responsible authors:                                                  #
#         Brigitte Verdonk                                               #
#         Annie Cuyt                                                     #
#                                                                        #
#  Contributors:                                                         #
#         Tarun Agarwal (05-07/2002)                                     #
#         Stefan Becuwe (07/2000- )                                      #
#         Johan Bogo (10/1998-09/1999)                                   #
#         Wim Dausy (10/2002-09/2003)                                    #
#         Tim Gevers (10-12/2000)                                        #
#         Matthias Huesken (02/2004- )                                   #
#         Debby Ooms (10/1996-09/1997)                                   #
#         Geert Vermuyten (10/1996-09/1997)                              #
#         Dennis Verschaeren (09/1996-06/2000)                           #
#                                                                        #
#  Copyright (C) 2000,2001,2002,2003,2004,2005                           #
#                Universiteit Antwerpen                                  #
#                                                                        #
#  This program can be obtained from the authors, free, but WITHOUT ANY  #
#  WARRANTY; without even the implied warranty of MERCHANTABILITY or     #
#  FITNESS FOR A PARTICULAR PURPOSE.                                     #
#                                                                        #
#  Contact:                                                              #
#       Brigitte.Verdonk@ua.ac.be                                        #
#       Departement Wiskunde en Informatica                              #
#       Universiteit Antwerpen                                           #
#       Middelheimlaan 1                                                 #
#       B-2020 Antwerpen, Belgium                                        #
#                                                                        #
##########################################################################


$Id: fpenv_MpIeee.cc 66 2005-05-18 13:04:54Z sbecuwe $

                                                                     
*/
/**	\file
 * 	\brief	Floating point environment of MpIeee (Conversions)
 */

// ----
// Includes
// ----
#include <cmath>
//UIA_EX	#include <strstream.h>	//reason: update pre-ANSI to standard library
#include <sstream>
#include <MpIeee.hh>
#include <ArithmosIO.hh>
#include <DriverFloatRepr.h> /* include after MpIeee.h to avoid redefinition of
rounding modes defined in fp.hh */

// ----
// Defines
// ----
#define BITSET(p,n)  (*((p)+((n)>>3))|=(1<<(7-((n)&7))))
#define BITCLR(p,n)  (*((p)+((n)>>3))&=~(1<<(7-((n)&7))))
#define BITVAL(p,n)  ((*((p)+((n)>>3))&(1<<(7-((n)&7))))!=0)
#define EXP_BIAS(size)      ((1L<<((unsigned long)(size)-1L))-1L)
#define EXP_MAX(size)       EXP_BIAS(size)
#define EXP_MIN(size)       (-(EXP_BIAS(size)-1))

extern int bitsForExp(long L, long U) ;
  
DriverFloatRepr::DriverFloatRepr(const MpIeee &M) { 
  unsigned long  expon;
  unsigned int i;
  unsigned long Bias = M.getU();
  double dsizeExpm1 = log2(M.getU()+1);
  // log2 returns an MpIeee and default conversion to double is OK but 
  // default conversion to int is not OK; hence this patch
  // the problem only occurs on extended-based architectures 
  // it is not specific to MpIeee but also occurs
  // when using only standard C-functions log and log10 to compute log2


//UIA_EX  sizeExp = dsizeExpm1+1;	//reason: assignment to int from double
  sizeExp = (int)dsizeExpm1+1;
  sizeMant = M.getPrecision();
  mant = Bitstring(sizeMant);
  exp = Bitstring(sizeExp);
  if (M.getSign() == mpMinus)
    sign = 1;
  else
    sign = 0;
  if (M.isZero()) {
    // initialized to zero
  }
  else if (M.isInf()) {
    
    for (i = 0;i < sizeExp; i++)
      exp.PutBit(i,1);
    mant.PutBit(0,1);
    for (i = 1;i < sizeMant; i++)
      mant.PutBit(i,0);
  }
  else if (M.isNan()) {
    for (i = 0;i < sizeExp; i++)
      exp.PutBit(i,1);
    mant.PutBit(0,1);
    mant.PutBit(1,1);
    for (i = 2;i < sizeMant; i++)
      mant.PutBit(i,0);
  }
  else {
    if (M.getExponent() != (M.getL() - 1)) {
      expon = M.getExponent() + Bias;
      for (int i = sizeExp - 1;i >= 0; i--) {
//UIA_EX        if (fmod(expon,2) != 0)	//reason: call of overloaded function 'fmod' ambiguous
        if ((double)fmod((double)expon,2) != 0)
          exp.PutBit(i,1);
        expon /= 2;
      }
    }
    else {
      for (unsigned int i = 0;i < sizeExp-1; i++)
        exp.PutBit(i,0);
      if (M[1] == 1)
        exp.PutBit(sizeExp-1,1);
      else
        exp.PutBit(sizeExp-1,0);
    }
    for (unsigned int i = 0;i < sizeMant; i++) 
//UIA_EX      mant.PutBit(i,M[i+1]);	//reason: passing `const double' for argument 2 of `int Bitstring::PutBit(long unsigned int, unsigned int)'
      mant.PutBit(i,(unsigned)M[i+1]);
  } 
}

MpIeee DriverFloatRepr::to()
{
  unsigned long int expon = 0;
//UIA_EX_DELETED  unsigned long int signexp;	//reason: unused
  unsigned int i,Bias;
  
  MpIeee::fpEnv.setRadix(2);
  MpIeee::fpEnv.setExponentSize(sizeExp);

  MpIeee tmp(FPParams(2, sizeMant, sizeExp));

  Bias=tmp.getU();
  
  
  if (sign == 0) {
    tmp.setSign(mpPlus);
  }
  else {
    tmp.setSign(mpMinus);
  }
  
//UIA_EX  for (i = 0;i < sizeExp-1; i++) {	//reason: comparison between signed and unsigned
  for (i = 0;i < (unsigned)sizeExp-1; i++) {

  if (exp.GetBit(i) == 1)
      expon += 1;
    expon *= 2;
  } 
  if (exp.GetBit(sizeExp - 1) == 1)
    expon += 1;
  if (expon == 2 * Bias + 1) {
    i = 1; 
//UIA_EX    while ((i < sizeMant) && (mant.GetBit(i) == 0)) i++; 	//reason: comparison between signed and unsigned
    while ((i < (unsigned)sizeMant) && (mant.GetBit(i) == 0)) i++; 
//UIA_EX    if (i == sizeMant)	//comparisong between signed and unsigned
    if (i == (unsigned)sizeMant)
      tmp.setInf(tmp.getSign());
    else
      tmp.setNan();
  } // if
  else {
    tmp.setExponent(expon - Bias);  
//UIA_EX    for (i = 0;i < sizeMant; i++)	//reason: comparison between signed and unsigned
    for (i = 0;i < (unsigned)sizeMant; i++)
      tmp.setDigit( i + 1, mant.GetBit( i ) );
  } // else
  
  return tmp;
}


void DriverFloatRepr::SetLibRound()     
{ 
  
  switch (GetFPRound())
    {
    case RM_NEAR:
      MpIeee::fpEnv.setRoundingMode(csRoundToNearest);
      break;
    case RM_ZERO:
      MpIeee::fpEnv.setRoundingMode(csRoundToZero);
      break;
    case RM_UP:
      MpIeee::fpEnv.setRoundingMode(csRoundUp);
      break;
    case RM_DOWN:
      MpIeee::fpEnv.setRoundingMode(csRoundDown);
      break;
    }
}

void DriverFloatRepr::SetLibEnvironment()
{
      MpIeee::fpEnv.clearStatusFlags();
}

void DriverFloatRepr::GetLibExceptions()
{
  ExceptionsType excep = MpIeee::fpEnv.checkStatusFlags();
  if (excep &  csDivisionByZero)
    SetFPDivByZero();
  if (excep &  csUndefinedResult) 
    SetFPInvalid();
  if (excep &  csUnderflow)
    SetFPUnderflow();
  if (excep &  csOverflow)
    SetFPOverflow();
  if (excep &  csInexactResult)
    SetFPInexact();
  MpIeee::fpEnv.clearStatusFlags();
}

DriverFloatRepr::DriverFloatRepr(long i) {
 
  Bitstring temp(32);
  hidden = 0;
  sizeMant = 32;
  sizeExp = 0;
  mant = Bitstring(sizeMant);
  exp = Bitstring();
  temp[0] = i;
  
  for (unsigned int j = 0;j < sizeMant;j++)
    mant.PutBit(j,temp.GetBit(j));
  
}

DriverFloatRepr::DriverFloatRepr(unsigned long i) {
  Bitstring temp(32);
  hidden = 0;
  sizeMant = 32;
  sizeExp = 0;
  mant = Bitstring(sizeMant);
  exp = Bitstring();
  temp[0] = i;
  for (unsigned int j = 0;j < sizeMant;j++)
    mant.PutBit(j,temp.GetBit(j));
}

DriverFloatRepr::DriverFloatRepr(long long int l) {
  unsigned long * tmparray;
  Bitstring temp(64);

  sizeMant = 64;
  sizeExp = 0;
  mant = Bitstring(sizeMant);
  exp = Bitstring();
  tmparray = (unsigned long *)&l;
  if (Endian == MYLITTLE_ENDIAN)
    {
      temp[0] = tmparray[1];
      temp[1] = tmparray[0];
    }
  else 
    {
      temp[0] = tmparray[0];
      temp[1] = tmparray[1];
    }
  for (unsigned int j = 0;j < sizeMant;j++)
    mant.PutBit(j,temp.GetBit(j));
}

DriverFloatRepr::DriverFloatRepr(unsigned long long int l) {
  unsigned long * tmparray;
  Bitstring temp(64);

  sizeMant = 64;
  sizeExp = 0;
  mant = Bitstring(sizeMant);
  exp = Bitstring();
  tmparray = (unsigned long *)&l;
  if (Endian == MYLITTLE_ENDIAN)
    {
      temp[0] = tmparray[1];
      temp[1] = tmparray[0];
    }
  else 
    {
      temp[0] = tmparray[0];
      temp[1] = tmparray[1];
    }
  for (unsigned int j = 0;j < sizeMant;j++)
    mant.PutBit(j,temp.GetBit(j));
}

int DriverFloatRepr::toint() {
  return (int&)mant[0];
}

unsigned int DriverFloatRepr::touint() {
  return (unsigned int&)mant[0];
}

long long DriverFloatRepr::tolonglong() {
  unsigned long tmparray[2];

  if (Endian == MYLITTLE_ENDIAN)
    {
      tmparray[0] = mant[1];
      tmparray[1] = mant[0];
    }
  else 
    {
      tmparray[0] = mant[0];
      tmparray[1] = mant[1];
    }
  
  return (long long &)*tmparray;
}

unsigned long long DriverFloatRepr::toulonglong() {
  unsigned long tmparray[2];
  if (Endian == MYLITTLE_ENDIAN)
    {
      tmparray[0] = mant[1];
      tmparray[1] = mant[0];
    }
  else 
    {
      tmparray[0] = mant[0];
      tmparray[1] = mant[1];
    }
  return (unsigned long long &)*tmparray;
}
