 /*
##########################################################################
#                                                                        #
# 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_SunSparc_for.cc 55 2005-01-26 16:59:10Z huesken $

                                                                     
*/
// ----
// Extern fortran functions
// ----
extern "C" {
void setround_(int&);
void getexcept_(int&);
void addf_(float&,float&,float&) ;
void addd_(double&,double&,double&) ;
void addl_(long double&,long double&,long double&) ;
void mulf_(float&,float&,float&) ;
void muld_(double&,double&,double&) ;
void mull_(long double&,long double&,long double&) ;
void divf_(float&,float&,float&) ;
void divd_(double&,double&,double&) ;
void divl_(long double&,long double&,long double&) ;
void remf_(float&,float&,float&) ;
void remd_(double&,double&,double&) ;
void reml_(long double&,long double&,long double&) ;
void sqrtf_(float&,float&) ;
void sqrtd_(double&,double&) ;
void sqrtl_(long double&,long double&);
void rintegralf_(float&,float&) ;
void rintegrald_(double&,double&) ;
void rintegrall_(long double&,long double&) ;
void rtld_(long double&,double&) ; 
void rif_(float&,long int&) ;
void rid_(double&,long int&) ;
void ril_(long double&,long int&) ;
void cif_(float&,long int&) ;
void cid_(double&,long int&) ;
void cil_(long double&,long int&) ;
void ri64f_(float&,unsigned long long int&) ;
void ri64d_(double&,unsigned long long int&) ;
void ri64l_(long double&,unsigned long long int&) ;
void ci64f_(float&,long long int&) ;
void ci64d_(double&,long long int&) ;
void ci64l_(long double&,long long int&) ;
void b2df_(int&,float&,char&);
void b2dd_(int&,double&,char&);
void b2dl_(int&,long double&,char&);
void d2bf_(float&,char&);
void d2bd_(double&,char&);
void d2bl_(long double&,char&);
}

// ----
// Includes
// ----
#include <cmath>
#include <DriverFloatRepr.h>

void DriverFloatRepr::SetLibRound()
{
  int i;
  switch (GetFPRound())
    {
    case RM_NEAR:
      i = 1;
      break;
    case RM_ZERO:
      i = 2;
      break;
    case RM_UP:
      i = 3;
      break;
    case RM_DOWN:
      i = 4;
      break;
    }
  setround_(i);
}

void DriverFloatRepr::SetLibEnvironment()
{
  SetLibRound();
}

void DriverFloatRepr::GetLibExceptions()
{
  int excep;
  getexcept_(excep);
  if (excep & 0x02 )
    SetFPDivByZero();
  if (excep & 0x10 )
    SetFPInvalid();
  if (excep & 0x04 )
    SetFPUnderflow();
  if (excep & 0x08 )
    SetFPOverflow();
  if (excep & 0x01)
    SetFPInexact(); 
}

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

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

  temp[0] = (unsigned long &)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);
  int i;

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

  unsigned long *tmparray;
  tmparray = (long unsigned int *)&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);
  int i;
  hidden = 1;
  sizeMant = 112;
  sizeExp = 15;
  mant = Bitstring(sizeMant);
  exp = Bitstring(sizeExp);

  unsigned long *tmparray;
  tmparray = (long unsigned int *)&l;
  if (Endian == MYLITTLE_ENDIAN)
    {
      temp[0] = tmparray[3];
      temp[1] = tmparray[2];
      temp[2] = tmparray[1];
      temp[3] = tmparray[0];
    }
  else 
    {
      temp[0] = tmparray[0];
      temp[1] = tmparray[1];
      temp[2] = tmparray[2];
      temp[3] = tmparray[3];
    }
  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 i) {
  Bitstring temp(32);
  hidden = 0;
  sizeMant = 32;
  sizeExp = 0;
  mant = Bitstring(sizeMant);
  exp = Bitstring();
  temp[0] = i;
  for (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 (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 (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 (int j = 0;j < sizeMant;j++)
    mant.PutBit(j,temp.GetBit(j));
}

float DriverFloatRepr::tofloat() {
  Bitstring temp(32);
  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);
  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));

  unsigned long 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(128); // quadruple
  int i=0;
  int extra = 0;

  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));
  
  unsigned long tmparray[4];

  if (Endian == MYLITTLE_ENDIAN)
    {
      tmparray[0] = temp[3];
      tmparray[1] = temp[2];
      tmparray[2] = temp[1];
      tmparray[3] = temp[0];

    }
  else 
    {
      tmparray[0] = temp[0];
      tmparray[1] = temp[1];
      tmparray[2] = temp[2];
      tmparray[3] = temp[3];
    }

  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() {
  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 int&)*tmparray;
}

unsigned long long int 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 int&)*tmparray;
}
