 /*
##########################################################################
#                                                                        #
# 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_IntelPentium_cpp.cc 78 2005-11-02 20:14:19Z huesken $

                                                                     
*/

// ----
// Includes
// ----

#include <Types.h>
#include <DriverFloatRepr.h>
#include <cmath>
#include <cstdlib>
#include <sstream>
#include <string>
#include <fenv.h>
#include "myfenv.h"

// ----
// Defines
// ----
#define ROUNDTN                 FE_TONEAREST
#define ROUNDUP                 FE_UPWARD
#define ROUNDDN                 FE_DOWNWARD
#define ROUNDTZ                 FE_TOWARDZERO
#define IEEEDEFAULTENV          FE_TONEAREST
#define FP_OVERFLOW             FE_OVERFLOW
#define FP_UNDERFLOW            FE_UNDERFLOW
#define FP_INVALID              FE_INVALID
#define FP_INEXACT              FE_INEXACT
#define FP_DIVBYZERO            FE_DIVBYZERO

void DriverFloatRepr::SetLibRound() {
  switch (GetFPRound())
    {
    case RM_NEAR:
      fesetround(ROUNDTN);
      break;
    case RM_ZERO:
      fesetround(ROUNDTZ);
      break;
    case RM_UP:
      fesetround(ROUNDUP);
      break;
    case RM_DOWN:
      fesetround(ROUNDDN);
      break;
    }
}

void DriverFloatRepr::SetLibEnvironment() { 
  SetLibRound();
  if (!use_extended_prec)
    {
      if ((sizeExp == 8) && (sizeMant == 23) && hidden)
        fesetprecision(FE_FLTPREC);
      else if ((sizeExp == 11) && (sizeMant == 52) && hidden)
        fesetprecision(FE_DBLPREC);
    }
  else
    {
      fesetprecision(FE_LDBLPREC);
    }
  feclearexcept(FE_ALL_EXCEPT);
}

void DriverFloatRepr::GetLibExceptions() {
  if (fetestexcept(FP_DIVBYZERO) )
    SetFPDivByZero();
  if (fetestexcept(FP_INVALID) )
    SetFPInvalid();
  if (fetestexcept(FP_UNDERFLOW) )
    SetFPUnderflow();
  if (fetestexcept(FP_OVERFLOW) )
    SetFPOverflow();
  if (fetestexcept(FP_INEXACT) )
    SetFPInexact();
    
  feclearexcept(FE_ALL_EXCEPT);
}

DriverFloatRepr::DriverFloatRepr(float f) {
  Bitstring temp(32);
  unsigned int i;

  hidden = 1;
  sizeMant = 23;
  sizeExp = 8;
  mant = Bitstring(sizeMant);
  exp = Bitstring(sizeExp);

  temp[0] = (ulong32 &)f;
  sign = temp.GetBit(0);
  for (i = 0; i < sizeExp;i++)
    exp.PutBit(i,temp.GetBit(i+1));
  for (i = 0;i < sizeMant;i++)
    mant.PutBit(i,temp.GetBit(i+sizeExp+1));
}

DriverFloatRepr::DriverFloatRepr(double d) {
  Bitstring temp(64);
  unsigned int i;

  hidden = 1;
  sizeMant = 52;
  sizeExp = 11;
  mant = Bitstring(sizeMant);
  exp = Bitstring(sizeExp);

  ulong32 *tmparray;
  tmparray = (ulong32 *)&d;
  if (Endian == MYLITTLE_ENDIAN)
    {
      temp[0] = tmparray[1];
      temp[1] = tmparray[0];
    }
  else 
    {
      temp[0] = tmparray[0];
      temp[1] = tmparray[1];
    }
  sign = temp.GetBit(0);
  for (i = 0; i < sizeExp;i++)
    exp.PutBit(i,temp.GetBit(i+1));
  for (i = 0;i < sizeMant;i++)
    mant.PutBit(i,temp.GetBit(i+sizeExp+1));
}

DriverFloatRepr::DriverFloatRepr(long double l) {
  Bitstring temp(128);
  unsigned int i;
  hidden = 0;
  sizeMant = 64;
  sizeExp = 15;

  mant = Bitstring(sizeMant);
  exp = Bitstring(sizeExp);

  ulong32 *tmparray;
  tmparray = (ulong32 *)&l;
      temp[0] = tmparray[2];
      temp[1] = tmparray[1];
      temp[2] = tmparray[0];
      temp << 16;
  sign = temp.GetBit(0);
  for (i = 0; i < sizeExp;i++)
    exp.PutBit(i,temp.GetBit(i+1));
  for (i = 0;i < sizeMant;i++)
    mant.PutBit(i,temp.GetBit(i+sizeExp+1));
}

DriverFloatRepr::DriverFloatRepr(long32 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(ulong32 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) {
  ulong32 * tmparray;
  Bitstring temp(64);

  sizeMant = 64;
  sizeExp = 0;
  mant = Bitstring(sizeMant);
  exp = Bitstring();
  tmparray = (ulong32 *)&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) {
  ulong32 * tmparray;
  Bitstring temp(64);

  sizeMant = 64;
  sizeExp = 0;
  mant = Bitstring(sizeMant);
  exp = Bitstring();
  tmparray = (ulong32 *)&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));
}

float DriverFloatRepr::tofloat() {
  Bitstring temp(32);
  unsigned int i;

  if(sign)
    temp.PutBit(0,1);
  for (i = 1; i <= sizeExp;i++)
    temp.PutBit(i,exp.GetBit(i-1));
  for (i = sizeExp + 1;i < sizeExp + 1 + sizeMant;i++)
    temp.PutBit(i,mant.GetBit(i-sizeExp-1));

  return *((float *)(&temp[0]));
}
 
double DriverFloatRepr::todouble() {
  Bitstring temp(64);
  unsigned int i;

  if(sign)
    temp.PutBit(0,1);
  for (i = 1; i <= sizeExp;i++)
    temp.PutBit(i,exp.GetBit(i-1));
  for (i = sizeExp + 1;i < sizeExp + 1 + sizeMant;i++)
    temp.PutBit(i,mant.GetBit(i-sizeExp-1));

  ulong32 tmparray[2];
  if (Endian == MYLITTLE_ENDIAN)
    {
      tmparray[0] = temp[1];
      tmparray[1] = temp[0];
    }
  else 
    {
      tmparray[0] = temp[0];
      tmparray[1] = temp[1];
    }
  return *((double *)tmparray);
}
 
long double DriverFloatRepr::tolongdouble() {
  Bitstring temp(96); // 80-bit
  unsigned int i=0;
  int extra = 0;
  extra += 16;
  if(sign)
    temp.PutBit(i+extra,1);
  for (i = 1; i <= sizeExp;i++)
    temp.PutBit(i+extra,exp.GetBit(i-1));

  for (i = sizeExp + 1;i < sizeExp + 1 + sizeMant;i++)
    temp.PutBit(i+extra,mant.GetBit(i-sizeExp-1));
  
  ulong32 tmparray[4];
      tmparray[0] = temp[2];
      tmparray[1] = temp[1];
      tmparray[2] = temp[0];

  return *((long double *)tmparray);
}

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

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

long long int DriverFloatRepr::tolonglong() {
  ulong32 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 int *)tmparray);
}

unsigned long long int DriverFloatRepr::toulonglong() {
  ulong32 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 int *)tmparray);
}
