/*
 *  Copyright (C) 2000 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#undef max
#undef min

#ifndef _GIAC_FIRST_H_
#define _GIAC_FIRST_H_

#ifdef __VISUALC__ 
// Visual C++ is compiling
#define VISUALC
typedef long pid_t;
typedef __int64 longlong ;
typedef unsigned __int64 ulonglong ;
#ifndef M_PI
#define M_PI       3.14159265358979323846
#endif
#define YY_NO_UNISTD_H
#ifndef _HAS_ITERATOR_DEBUGGING
#define _HAS_ITERATOR_DEBUGGING 0
#endif
#ifndef _ITERATOR_DEBUG_LEVEL
#define _ITERATOR_DEBUG_LEVEL 0
#endif
#ifndef _SECURE_SCL
#define _SECURE_SCL 0
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE 1
#endif
#else // __VISUALC__
typedef long long longlong;
typedef unsigned long long ulonglong;
#ifdef __x86_64__
  typedef int int128_t __attribute__((mode(TI)));
  typedef unsigned int uint128_t __attribute__((mode(TI)));
#ifndef INT128
#define INT128 1
#endif
#endif // __x86_64__
#endif // __VISUALC__

#ifndef __x86_64__
#ifdef SMARTPTR64
#undef SMARTPTR64
#endif // SMARTPTR64
#ifdef _I386_
#undef _I386_
#endif
#endif // not defined __x86_64__

#ifdef USE_GMP_REPLACEMENTS
#undef HAVE_GMPXX_H
#undef HAVE_LIBMPFR
#include "gmp_replacements.h"
#else
#include <gmp.h>
#endif

#include <cassert>

class init_gmp_memory 
{
	static int refcount;
	public:
	init_gmp_memory();
	~init_gmp_memory();
};
extern init_gmp_memory init_gmp_memory_instance;

#ifdef BCD

#include <stdlib.h>
#include "bcd_float.h" 
// abstract structure for BCD float operations
// bcd_float.h should define a type for bcd_float, 
// that fits into a gen (it can be a 64 bits integer but only 56 bits avail.)
// For accuracy, the BCD floats should have an expanded form
// of type accurate_bcd_float, that one can get using 
//   accurate_bcd_float * fExpand(bcd_float,accurate_bcd_float *)
// This accurate value is returned from a gen g using
//   gentobcd(g,accurate_bcd_float *)
// bcd_float.h should define the following operations 
//   fradd_g, frsub_g, fmul_g, fdiv_g, fchs_g, fpow_g
//   fLT_g, fGT_g (strict comparison, return bool), fEQ_g,
//   fabs_g, fsqrt_g, fZero_g (is ==0)
//   bcd_zero, bcd_set_double, bcd_get_double, bcd_set_int, bcd_get_int, 
struct giac_bcdfloat {
  bcd_float f;
  giac_bcdfloat(const bcd_float & _f){f=_f;}
  giac_bcdfloat(int i) {f=bcd_set_int(i);}
  giac_bcdfloat(const giac_bcdfloat & _f) {f=_f.f;}
  giac_bcdfloat(){f=bcd_zero;}
  giac_bcdfloat(double d){ f=bcd_set_double(d);}
};
typedef giac_bcdfloat giac_float;
inline void print_float(const giac_bcdfloat & f,char * ch,u32 bcd_decpoint,u32 bcd_mantissa,u32 bcd_flags){
  bcd_print(f.f,ch,bcd_decpoint,bcd_mantissa,bcd_flags);
}
inline giac_bcdfloat operator + (const giac_bcdfloat & f1,const giac_bcdfloat & f2){
  return fradd_g(f1.f,f2.f);
}
inline giac_bcdfloat operator += (giac_bcdfloat & f1,const giac_bcdfloat & f2){
  f1.f=fradd_g(f1.f,f2.f);
  return f1;
}
inline giac_bcdfloat operator - (const giac_bcdfloat & f1,const giac_bcdfloat & f2){
  return frsub_g(f1.f,f2.f);
}
inline giac_bcdfloat operator -= (giac_bcdfloat & f1,const giac_bcdfloat & f2){
  f1.f=frsub_g(f1.f,f2.f);
  return f1;
}
inline giac_bcdfloat operator - (const giac_bcdfloat & f1){
  return fchs_g(f1.f);
}
inline giac_bcdfloat operator * (const giac_bcdfloat & f1,const giac_bcdfloat & f2){
  return fmul_g(f1.f,f2.f);
}
inline giac_bcdfloat operator *= (giac_bcdfloat & f1,const giac_bcdfloat & f2){
  f1.f=fmul_g(f1.f,f2.f);
  return f1;
}
inline giac_bcdfloat operator / (const giac_bcdfloat & f1,const giac_bcdfloat & f2){
  return fdiv_g(f1.f,f2.f);
}
inline giac_bcdfloat operator /= (giac_bcdfloat & f1,const giac_bcdfloat & f2){
  f1.f=fdiv_g(f1.f,f2.f);
  return f1;
}
inline bool operator == (const giac_bcdfloat & f1,const giac_bcdfloat & f2){
  return fEQ_g(f1.f,f2.f);
}
inline bool operator > (const giac_bcdfloat & f1,const giac_bcdfloat & f2){ return fGT_g(f1.f,f2.f); }
inline bool operator < (const giac_bcdfloat & f1,const giac_bcdfloat & f2){ return fLT_g(f1.f,f2.f); }
inline bool operator >= (const giac_bcdfloat & f1,const giac_bcdfloat & f2){ return fGE_g(f1.f,f2.f); }
inline bool operator <= (const giac_bcdfloat & f1,const giac_bcdfloat & f2){ return fLE_g(f1.f,f2.f); }
inline double get_double(const giac_bcdfloat & f) { 
  // FIXME
  char ch[32]; char * endchar;
  print_float(f.f,ch,'.'|('E'<<16)|(' '<<24),12+(15<<8),0);
  return strtod(ch,&endchar); 
}
inline int get_int(const giac_bcdfloat & f) { return bcd_get_int(f.f);}
inline giac_bcdfloat fabs (const giac_bcdfloat & f1){ return fabs_g(f1.f);}
inline int fsign (const giac_bcdfloat & f1){ return fZero_g(f1.f)?0:(fPos_g(f1.f)?1:-1); }
inline giac_bcdfloat fsqrt (const giac_bcdfloat & f1){ return fsqrt_g(f1.f); }
inline giac_bcdfloat finv (const giac_bcdfloat & f1){ return finv_g(f1.f); }
inline giac_bcdfloat fsquare (const giac_bcdfloat & f1){ return fsquare_g(f1.f); }
inline giac_bcdfloat fpow(const giac_bcdfloat & f1,const giac_bcdfloat & f2) {   return fpow_g(f1.f,f2.f); }
inline giac_bcdfloat fround(const giac_bcdfloat & f1,int digits) {   return frnd_g(f1.f,digits,true); }
inline giac_bcdfloat ftrunc(const giac_bcdfloat & f1,int digits) {   return ftrunc_g(f1.f,digits,true); }
inline giac_bcdfloat ffloor(const giac_bcdfloat & f){ return ffloor_g(f.f);}
inline giac_bcdfloat fceil(const giac_bcdfloat & f){ return fceil_g(f.f);}
inline giac_bcdfloat fsin(const giac_bcdfloat & f,int angle_mode){ return fsin_g(f.f,TAngleMode(angle_mode));}
inline giac_bcdfloat fcos(const giac_bcdfloat & f,int angle_mode){ return fcos_g(f.f,TAngleMode(angle_mode));}
inline giac_bcdfloat ftan(const giac_bcdfloat & f,int angle_mode){ return ftan_g(f.f,TAngleMode(angle_mode));}
inline giac_bcdfloat fcot(const giac_bcdfloat & f,int angle_mode){ return fcot_g(f.f,TAngleMode(angle_mode));}
inline giac_bcdfloat fasin(const giac_bcdfloat & f,int angle_mode){ return fasin_g(f.f,TAngleMode(angle_mode));}
inline giac_bcdfloat facos(const giac_bcdfloat & f,int angle_mode){ return facos_g(f.f,TAngleMode(angle_mode));}
inline giac_bcdfloat fatan(const giac_bcdfloat & f,int angle_mode){ return fatan_g(f.f,TAngleMode(angle_mode));}
inline giac_bcdfloat facot(const giac_bcdfloat & f,int angle_mode){ return facot_g(f.f,TAngleMode(angle_mode));}
inline giac_bcdfloat fsinh(const giac_bcdfloat & f){ return fsinh_g(f.f);}
inline giac_bcdfloat fcosh(const giac_bcdfloat & f){ return fcosh_g(f.f);}
inline giac_bcdfloat ftanh(const giac_bcdfloat & f){ return ftanh_g(f.f);}
inline giac_bcdfloat fasinh(const giac_bcdfloat & f){ return fasinh_g(f.f);}
inline giac_bcdfloat facosh(const giac_bcdfloat & f){ return facosh_g(f.f);}
inline giac_bcdfloat fatanh(const giac_bcdfloat & f){ return fatanh_g(f.f);}
inline giac_bcdfloat flog(const giac_bcdfloat & f){ return fln_g(f.f);}
inline giac_bcdfloat fln(const giac_bcdfloat & f){ return fln_g(f.f);}
inline giac_bcdfloat flnp1(const giac_bcdfloat & f){ return flnp1_g(f.f);}
inline giac_bcdfloat fexp(const giac_bcdfloat & f){ return fexp_g(f.f);}
inline giac_bcdfloat fexpm(const giac_bcdfloat & f){ return fexpm_g(f.f);}
inline giac_bcdfloat flog10(const giac_bcdfloat & f){ return flog_g(f.f);}
inline giac_bcdfloat falog10(const giac_bcdfloat & f){ return falog_g(f.f);}
inline giac_bcdfloat fmod(const giac_bcdfloat & f1,const giac_bcdfloat & f2){ return fmod_g(f1.f,f2.f);}
inline giac_bcdfloat fnthroot(const giac_bcdfloat & f1,const giac_bcdfloat & f2){ return fnthroot_g(f1.f,f2.f);}
inline giac_bcdfloat fmax(const giac_bcdfloat & f1,const giac_bcdfloat & f2){ return fmax_g(f1.f,f2.f);}
inline giac_bcdfloat fmin(const giac_bcdfloat & f1,const giac_bcdfloat & f2){ return fmin_g(f1.f,f2.f);}
inline bool is_exactly_zero(const giac_bcdfloat & f){ return fZero_g(f.f);}
inline bool is_integer(const giac_bcdfloat & f){ return fInteger_g(f.f); }
inline bool is_positive(const giac_bcdfloat & f){ return fPos_g(f.f);}
inline bool fis_nan(const giac_bcdfloat & f){ return fNaN_g(f.f); }
inline giac_bcdfloat strtobcd(const char *nptr,const char **endptr,char decpoint,char thousand,int base){ return fstrtobcd(nptr,endptr,decpoint,thousand,base); }
#else // defined BCD

#include <cmath>
typedef float giac_float;
inline bool is_exactly_zero(float f){ return f==0;}
inline double get_double(float f) { return f;}
inline int get_int(float f) { return int(f);}
inline int fsign (float f1){return f1==0?0:(f1>0?1:-1);}
float fsqrt (float f1);
void print_float(const giac_float & f,char * ch);
inline float fpow(float f1,float f2){ return std::pow(f1,f2); }
inline float ffloor(float f1){ return std::floor(f1); }
inline float finv(float f1){ return 1/f1; }

#endif // BCD

#endif // _GIAC_FIRST_H_
