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

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

#include <cmath>
#include <Types.h>
#include <DriverFloatRepr.h>
#include <iostream>
#include <string>

#define NDIGMXX 256 // max value for NDIG IN PACKAGE
#define breedte NDIGMXX + 2


void DriverFloatRepr::SetLibRound( )
{
  switch ( GetFPRound( ) ) {
    case RM_DOWN:
      FMSETVAR((char *) " KROUND = -1        " );
      break;
    case RM_NEAR:
      FMSETVAR((char *) " KROUND = 1         " );
      break;
    case RM_ZERO:
      FMSETVAR((char *) " KROUND = 0         " );
      break;
    case RM_UP:
      FMSETVAR((char *) " KROUND = 2         " );
      break;
  }
}

void DriverFloatRepr::SetLibEnvironment( )
{
  // clear all floating-point exceptions
  ;
}

void DriverFloatRepr::GetLibExceptions( )
{
  ;
}

void DriverFloatRepr::toDriverFloatRepr( Bitstring m,Bitstring e,int h, int signf )
/* Conversion from DriverFloatRepr to FMNUMBER */
{
  long32 i;
  long32 tmp;

  // alles op nul zetten in de DriverFloatRepr-array
  for ( int tt = 0; tt < breedte; tt++ )  value[ tt ]  = 0;

  // copy the DriverFloatRepr mantissa to FMNUMBER
  for( i = 0; i < m.Length( );i++ ) {
    if( m.GetBit( i ) ==1 )  value[ 2+i ] =( double ) 1;
  }

  // conversie van een biased Bitstring-exponent naar een DriverFloatRepr-exponent
  if ( e[ 0 ]  != 0 )  { // no support for denormals
    ulong32 bias = ( 2<<( e.Length( ) -2 ) ) -1;
    tmp = ( e[ 0 ] >>( 32-e.Length( ) ) ) -bias;
    tmp++;
  } else
    tmp = 0;

  value[ 0 ] =sizeMant+h;  // dit is de precisie, het aantal binaire bits.
  value[ 1 ] =tmp;

  // dit is iets raar. Als het teken + is, dan sign is 501 bij het binnenkomen.
  if (  signf == 501 )  Sign( 0 );
  value[ 2 ]  *= ( ( Sign( ) ==0 ) ?1:-1 );
}

void DriverFloatRepr::fromDriverFloatRepr( Bitstring& m,Bitstring& e,int h )
/* Conversion from FMNUMBER to DriverFloatRepr */
{
  double  dexp;
  int start = 2;
  unsigned int tt;
  int flag;

  m = Bitstring( sizeMant );
  e = Bitstring( sizeExp );
  
  FMFLAG( &flag );
  if ( flag == -4 )  // INVALID INPUT ARGUMENTS
  {
    // Construct Quiet NaN
    // cout << "NaN" << flush << endl;
    for ( tt = 0; tt < sizeMant; tt ++ )
      m.PutBit( tt,0 );
    for ( tt = 0; tt < sizeExp; tt ++ )
      e.PutBit( tt,0 );
    Sign( 0 );
    return;
  }

  if ( value[ 2 ]  == 0 ) {
    for ( tt = 0; tt < sizeMant; tt ++ )
      m.PutBit( tt,0 );
    for ( tt = 0; tt < sizeExp; tt ++ )
      e.PutBit( tt,0 );
    Sign( 0 ); // no support for signed zeros
    return;
  }

  if ( value[ 2 ] <0 ) {
    value[ 2 ] *=-1;
    Sign( 1 );
  } else {
    Sign( 0 );
  }


  for( int index=start;index<( start+sizeMant );index++ ) {
    if( value[ index ] ==1 )
      m.PutBit( index - start,1 );
    else
      m.PutBit( index - start,0 );
  }

  dexp = value[ 1 ];
  dexp--;

  //de exponent is in biased notatie dus de "tmp" verhogen...
  dexp += pow( 2.0,(int)sizeExp-1 )  - 1;


  //omzetten van de exponent naar de originele bitstring
  for ( int i=sizeExp-1;i>=0;i-- )  {
    if ( dexp >= pow( 2.0 ,i ) )  {
      dexp -= pow( 2.0 ,i );
      e.PutBit( sizeExp-i-1,1 );
    } else
      e.PutBit( sizeExp-i-1,0 );
  }
}

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( 128 ); // quadruple
  unsigned 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 ) );

  ulong32 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( )
{
  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);
}

DriverFloatRepr::DriverFloatRepr( const DriverFloatRepr& source ) :FP( source )
{
//UIE_EX  int prec = ( int ) ( log( 2 ) *source.sizeMant );	//reason:unused

  value = new double[ breedte ];

  FMSETVAR((char *)" MBASE = 2           ");
  FMSETVAR((char *)" KWARN = 0           ");

}

DriverFloatRepr::DriverFloatRepr( ) :FP( )
{

  value = new double[ breedte ];

  /* no init value so we make the DriverFloatRepr number 0*/
  for ( int i = 0; i < breedte; i++ )  {
    value[ i ] =0;
  }
}

DriverFloatRepr::DriverFloatRepr( int m,int e,int h ) :FP( m,e,h )
{

  value = new double[ breedte ];
  FMSETVAR((char *)" MBASE = 2           ");
  if ( m==24 && e==8 ) { 
    FMSETVAR((char *)" NDIG = 24           ");
    FMSETVAR((char *)" MXEXP = 149         "); 
  } 
  else if ( m==53 && e==11 ) {
    FMSETVAR((char *)" NDIG = 53           ");
    FMSETVAR((char *)" MXEXP = 1074        "); 
  } 
  else {
    FMSETVAR((char *)" NDIG = 217          ");
    FMSETVAR((char *)" MXEXP = 16598       ");
  } 

   FMSETVAR((char *)" KWARN = 0           ");

  /* no init value so we make the DriverFloatRepr number 0*/
  value[ 0 ] =0;
  value[ 1 ] =0;
  value[ 2 ] =0;
}

DriverFloatRepr::DriverFloatRepr( Bitstring& fp, int m,int e,int h ) :FP( fp,m,e,h )
{

  value = new double[ breedte ];
  
  FMSETVAR((char *)" MBASE = 2           ");
  if ( m==24 && e==8 ) { 
    FMSETVAR((char *)" NDIG = 24           ");
    FMSETVAR((char *)" MXEXP = 149         "); 
  }
  else if ( m==53 && e==11 ) {
    FMSETVAR((char *)" NDIG = 53           ");
    FMSETVAR((char *)" MXEXP = 1074        "); 
  }
  else { 
    FMSETVAR((char *)" NDIG = 217          ");
    FMSETVAR((char *)" MXEXP = 16598       ");
  } 

  FMSETVAR((char *)" KWARN = 0           ");
 
  // toDriverFloatRepr(mant, exp, hidden, Sign());
}

void DriverFloatRepr::Reverse( Bitstring& b )
{
  char hlp[256];
  char *tmp = hlp;
  unsigned int k;

  //omkeren van de BitString b : "001" wordt ".100"
  b.BitstrToString( tmp );
  for(unsigned int j = 0;j< ( b.Length( ) /2 );j++ ) {
    k = tmp[ j ];
    tmp[ j ] =tmp[ b.Length( ) -j-1 ];
    tmp[ b.Length( ) -j-1 ]  = k;
  }
  b.Resize( 0 );
  b.StringToBitstr( tmp );
}
