#ifndef __FLOATBCD_AMV
	#define __FLOATBCD_AMV

#include <string>
#include <iostream>
#include <cctype>
#include "uintBCD.h"
#include "exception.h"
#include "algorithm.h"
#include "REEvaluator.h"
#include "function.h"
#include "stringAMV.h"
#include "binaryTree.h"
#include "mathAMV.h"
//#include "rationalMean.h"
#include "amvdefs.h"

/*
	La presente biblioteca tiene como objetivo permitir el manejo de
	números de punto flotante sin pérdida de precisión; ya que el
	coprocesador matemático no puede representar exactamente algunos
	números decimales, cosa que es necesaria para algunas aplicaciones.

	Es por ello que los números de punto flotante se manejan en el 
	formato BCD(Binary Coded Decimal, en español, decimal codificado
	en binario).

*/

namespace amv	{

//Función genérica para calcular el valor absoluto
//el tipo del parámetro debe aceptar el 0(cero) en su contructor
//y debe de manejar el operador >= y el - monario
/*definida en mathAMV.h
template <class type> inline type abs(const type &t)
{
return ((t>=type(0))? t: -t);
}
*/

template <class type>
type rootGomezMorin(const type &N,const type &i, const unsigned int it=10)
{//hallar primero una aproximacion
//type x("1.25");
type x(1);
for(unsigned int j=0; j<it; ++j)
	{
	x=(type(2)*N+(i-type(2))*(x^i))/(N/x+(i-type(1))*(x^(i-type(1))));
	}

return x;
}

template <class type>
type rootNewton(const type &N,const type &i, const unsigned int it=10)
{
//type x("1.25");
type x(1);
for(unsigned int j=0; j<it; ++j)
	{
	x=(N+(i-type(1))*(x^i))/(i*(x^(i-type(1))));
	}

return x;
}

/*****************************************************************/
//Definición de la clase floatBCD
/*****************************************************************/

class floatBCD	{
	public:
		typedef unsigned int fmtflags;
		static const fmtflags fix, sci;
	private:
		static fmtflags m_flags;
	static REEvaluator REEfloatBCD;
	uintBCD bcd;	//vector en el que se guardan los dígitos del número
	int posPoint;	//posición del punto decimal [0,número de dígitos-1],
	//si es igual al número de dígitos, la mantisa es entera,
	//de otro modo, el punto decimal va insertado implícitamente
	//en la posición que representa el número que contiene
	int exponent;	//exponent de la base 10 que multiplica a la mantisa
	int sign; //sign>0, positivo; !sign, cero, sign<0, negativo
	void normalize();
	void enforceExp(int nExp);	
	void doIntegerMantisa();
	public:
		static int precision;
		static bool eval(const char *number);
		floatBCD();
		floatBCD(const string &s);
		floatBCD(const char *number);
		floatBCD(const floatBCD &nBCD);
		floatBCD(int n, int exp=0);
		floatBCD(bool b);
		//operador de asignación
		floatBCD &operator=(const floatBCD &op2);
		floatBCD &operator+=(const floatBCD &op2);
		floatBCD &operator-=(const floatBCD &op2);
		floatBCD &operator*=(const floatBCD &op2);
		floatBCD &operator/=(const floatBCD &op2);
		floatBCD &operator^=(const floatBCD &op2);
		floatBCD &operator%=(const floatBCD &op2);
		//operadores aritméticos
		floatBCD operator+(const floatBCD &op2) const;
		floatBCD operator-(const floatBCD &op2) const;
		floatBCD operator*(const floatBCD &op2) const;
		floatBCD operator/(const floatBCD &op2) const;
		floatBCD operator-() const;
		floatBCD operator^(const floatBCD &op2) const;
		floatBCD operator%(const floatBCD &op2) const;
		//Operadores de incremento
		floatBCD &operator++();
		//operadores lógicos
		bool operator>(const floatBCD &op2) const;
		bool operator<(const floatBCD &op2) const;
		bool operator>=(const floatBCD &op2) const;
		bool operator==(const floatBCD &op2) const;
		//multiplicación y división por 10
		void mul10();
		void div10();
		void invertSign();
		int size() const;
		bool isInteger() const;
		bool isFraction() const;
		bool isPositive() const;
		bool isNegative() const;
		bool isZero() const;
		int getSign() const;
		int getExponent() const;
		floatBCD getIntegerPart() const;
		fmtflags flags() const { return m_flags; }
		fmtflags flags(fmtflags f) { fmtflags oldFlags=m_flags; m_flags=f; return oldFlags; }

		//friend floatBCD abs(const floatBCD &n);//tiene plantilla
		friend floatBCD fact(const floatBCD &n);
		friend floatBCD exp(const floatBCD &n);
		friend floatBCD log(const floatBCD &n);
		friend floatBCD ln(const floatBCD &n);
		friend floatBCD sin(const floatBCD &n);
		friend floatBCD sinh(const floatBCD &n);
		friend floatBCD asin(const floatBCD &n);
		friend floatBCD cos(const floatBCD &n);
		friend floatBCD cosh(const floatBCD &n);
		friend floatBCD acos(const floatBCD &n);
		friend floatBCD tan(const floatBCD &n);
		friend floatBCD tanh(const floatBCD &n);
		friend floatBCD atan(const floatBCD &n);
		friend floatBCD ctg(const floatBCD &n);
		friend floatBCD actg(const floatBCD &n);
		friend floatBCD sec(const floatBCD &n);
		friend floatBCD asec(const floatBCD &n);
		friend floatBCD csc(const floatBCD &n);
		friend floatBCD acsc(const floatBCD &n);
		//friend floatBCD sqrt(const floatBCD &n)
		friend floatBCD min1(const floatBCD &n1, const floatBCD &n2);
		friend floatBCD max1(const floatBCD &n1, const floatBCD &n2);
		friend floatBCD pow(const floatBCD &n, const floatBCD &nth);
		friend floatBCD root(const floatBCD &nth, const floatBCD &n);

		//operador de salida a un flujo
		friend ostream &operator<<(ostream &os, const floatBCD nBCD);
		friend istream &operator>>(istream &is, floatBCD &nBCD);

		static binaryTree<function<floatBCD> > getFunctionsTree(const floatBCD &f)
			{
			binaryTree<function<floatBCD> > t;
			t.insert(function<floatBCD>("fact",fact)),
			t.insert(function<floatBCD>("exp",exp)),
			t.insert(function<floatBCD>("log",log)),
			t.insert(function<floatBCD>("ln",ln)),
			t.insert(function<floatBCD>("sin",sin)),
			t.insert(function<floatBCD>("sinh",sinh)),
			t.insert(function<floatBCD>("asin",asin)),
			t.insert(function<floatBCD>("cos",cos)),
			t.insert(function<floatBCD>("cosh",cosh)),
			t.insert(function<floatBCD>("acos",acos)),
			t.insert(function<floatBCD>("tan",tan)),
			t.insert(function<floatBCD>("tanh",tanh)),
			t.insert(function<floatBCD>("atan",atan)),
			t.insert(function<floatBCD>("ctg",ctg)),
			t.insert(function<floatBCD>("actg",actg)),
			t.insert(function<floatBCD>("sec",sec)),
			t.insert(function<floatBCD>("asec",asec)),
			t.insert(function<floatBCD>("csc",csc)),
			t.insert(function<floatBCD>("acsc",acsc)),
			t.insert(function<floatBCD>("min",min1,function<floatBCD>::BINARY)),
			t.insert(function<floatBCD>("max",max1,function<floatBCD>::BINARY)),
			t.insert(function<floatBCD>("pow",pow,function<floatBCD>::BINARY)),
			t.insert(function<floatBCD>("root",root,function<floatBCD>::BINARY));

			return t;
			}

		static floatBCD e;//base de logaritmos
		static floatBCD pi;//constante del circunferencia
		static floatBCD fi;//proporción dorada

};

const floatBCD::fmtflags floatBCD::fix=0x0001, floatBCD::sci=0x0002;
floatBCD::fmtflags floatBCD::m_flags(floatBCD::sci);

REEvaluator floatBCD::REEfloatBCD("\\-?<[0-9]+<(.<[0-9]+)?<(e<\\-?<[0-9]+)?");
int floatBCD::precision=4;

floatBCD floatBCD::e="2.78";
floatBCD floatBCD::pi="3.141592654";
floatBCD floatBCD::fi="1.71";

/******************* Funciones privadas ***************************/

//elimina de la mantisa los ceros a la izquierda
//de los enteros y a la derecha de los decimales
inline void floatBCD::normalize()
{
if(!sign)
	return;
int zeros=0,i;

if(posPoint>0)
	{
	for(i=0; i<posPoint; ++i)
		{
		if(!bcd[i])
			{
			++zeros;
			}
		else
			{
			break;
			}
		}
	if(zeros)
		{
		if(zeros==bcd.size())
			{
			bcd=uintBCD();
			posPoint=0;
			exponent=0;
			sign=0;
			return;
			}
		else
			{
			if(posPoint==bcd.size())
				{
				bcd.resizeI(bcd.size()-zeros,0);
				posPoint=bcd.size();
				}
			else
				{
				bcd.resizeI(bcd.size()-zeros,0);
				posPoint-=zeros;
				}
			}
		}
	}
if(posPoint<bcd.size())
	{
	zeros=0;
	for(i=bcd.size()-1; i>=posPoint; --i)
		{
		if(!bcd[i])
			{
			++zeros;
			}
		else
			{
			break;
			}
		}
	if(zeros)
		{
		if(zeros==bcd.size())
			{
			bcd=uintBCD();
			posPoint=0;
			exponent=0;
			sign=0;
			return;
			}
		else
			{
			bcd.resize(bcd.size()-zeros,0);
			}
		}
	}
}

//convierte el número a uno equivalente
//con exponente nExp
inline void floatBCD::enforceExp(int nExp)
{
if(exponent==nExp || (!sign))
	return;

int dif=nExp-exponent;
exponent=nExp;
if(dif>0)
	{
	posPoint-=dif;
	if(posPoint<0)
		{
		bcd.resizeI(bcd.size()+abs(posPoint),0);
		posPoint=0;
		}
	}
else
	{
	posPoint+=abs(dif);
	if(posPoint>bcd.size())
		{
		bcd.resize(posPoint,0);
		}
	}
this->normalize();
}

//convierte la mantisa a un número entero
inline void floatBCD::doIntegerMantisa()
{
if(posPoint!=bcd.size())
	{
	exponent-=(bcd.size()-posPoint);
	posPoint=bcd.size();
	this->normalize();
	}
}

inline bool floatBCD::eval(const char *number)
{
return (REEfloatBCD.eval(number));
}

//********************* Funciones públicas **********************/

//constructor por omisión, inicializa el número a 0
inline floatBCD::floatBCD():
posPoint(0), exponent(0), sign(0)
{
}

inline floatBCD::floatBCD(const string &s)
{
string::const_iterator it(s.begin()), itPoint(find(s.begin(),s.end(),'.')), itExp(find(s.begin(),s.end(),'e'));
int length=s.size(), i, expDigits, exp=0, expSign;
char *pPos;
if(*it=='-')
	{
	sign=-1;
	++it;
	--length;
	}
else
	sign=1;

if(itExp!=s.end())
	{
	expDigits=s.end()-itExp;
	length-=expDigits;
	++itExp;
	if(itExp!=s.end())
		{
		if(*itExp=='-')
			{
			++itExp;
			expSign=-1;
			}

		while(itExp!=s.end())
			{
			exp=exp*10+AsciiBCD(*itExp);
			++itExp;
			}
		if(exp>0 && expSign<0)
			exp=-exp;
		}
	}

if(itPoint!=s.end())
	{
	posPoint=itPoint-it;
	--length;
	bcd.resize(length);
	for(i=0; i<posPoint; ++i)
		bcd[i]=AsciiBCD(*(it+i));
	for(++i; i<=length; ++i)
		bcd[i-1]=AsciiBCD(*(it+i));
	}
else
	{
	posPoint=length;
	bcd.resize(length);
	for(i=0; i<length; ++i)
		bcd[i]=AsciiBCD(*(it+i));
	}

for(i=0; i<bcd.size() && bcd[i]==0; ++i)
	;
if(i==bcd.size())
	{
	bcd=uintBCD();
	posPoint=0;
	exponent=0;
	sign=0;
	return;
	}
else
	{
	exponent=exp;
	this->normalize();
	}
}
//*************corregir descripcion
//constructor que recibe como parámetros una cadena que representa
//la mantisa y el exponente de la base 10, este último es opcional,
//cuando no se proporciona, se toma como 0
inline floatBCD::floatBCD(const char *number)
{
int length,i, exp=0;
const char *pPos;
if(*number=='-')
	{
	sign=-1;
	++number;
	}
else
	sign=1;

length=strlen(number);

if(pPos=strstr(number,"."))
	{
	posPoint=pPos-number;
	length-=1;
	bcd.resize(length);
	for(i=0; i<posPoint; ++i)
		bcd[i]=AsciiBCD(number[i]);
	for(++i; i<=length; ++i)
		bcd[i-1]=AsciiBCD(number[i]);
	}
else
	{
	posPoint=length;
	bcd.resize(length);
	for(i=0; i<length; ++i)
		bcd[i]=AsciiBCD(number[i]);
	}

for(i=0; i<bcd.size() && bcd[i]==0; ++i)
	;
if(i==bcd.size())
	{
	bcd=uintBCD();
	posPoint=0;
	exponent=0;
	sign=0;
	return;
	}
else
	{
	exponent=exp;
	this->normalize();
	}
}

//constructor de copia, para inicializar un nuevo objeto con otro
//del mismo tipo
inline floatBCD::floatBCD(const floatBCD &nBCD):
bcd(nBCD.bcd), posPoint(nBCD.posPoint),
exponent(nBCD.exponent), sign(nBCD.sign)
{
}

inline floatBCD::floatBCD(int n, int exp):
posPoint(0), exponent(exp), sign(0)
{
if(!n)
	return;

if(n>0)
	sign=1;
else
	{
	sign=-1;
	n=abs(n);
	}

int digits=0, temp(n);
while(temp)
	{
	++digits;
	temp/=10;
	}

bcd.resize(digits);

for(int i=digits-1, k=0; k<digits; ++k, --i)
	{
	bcd[i]=n%10;
	n/=10;
	}
posPoint=digits;
}

inline floatBCD::floatBCD(bool b)
{
if(b)
	{
	bcd.resize(1);
	bcd[0]=1;
	posPoint=1;
	exponent=0;
	sign=1;
	}
else
	{
	posPoint=0;
	exponent=0;
	sign=0;
	}
}

inline floatBCD &floatBCD::operator=(const floatBCD &op2)
{
bcd=op2.bcd;
posPoint=op2.posPoint;
exponent=op2.exponent;
sign=op2.sign;

return (*this);			
}

inline floatBCD &floatBCD::operator+=(const floatBCD &op2)
{
if(!sign)
	{
	*this=op2;
	return *this;
	}

if(!op2.sign)
	return *this;
floatBCD newOp2(op2);
newOp2.enforceExp(exponent);

int newLength,i,j,nI,nD, integersOp1, integersOp2, decimalsOp1, decimalsOp2;

integersOp1=posPoint;
integersOp2=newOp2.posPoint;
decimalsOp1=bcd.size()-posPoint;
decimalsOp2=newOp2.bcd.size()-newOp2.posPoint;

nI=(integersOp1>integersOp2)? (integersOp1+1): integersOp2+1;
nD=(decimalsOp1>decimalsOp2)? decimalsOp1: decimalsOp2;
newLength=nI+nD;

if(sign+newOp2.sign)
	{
	char carry=0, sum;

	uintBCD temp2(newLength);
	fill(temp2,0);

	for(i=nI-1, j=integersOp1-1; j>=0; --i, --j)
		temp2[i]=bcd[j];
	for(i=nI, j=integersOp1; j<bcd.size(); ++i, ++j)
		temp2[i]=bcd[j];

	for(j=newOp2.bcd.size()-1; j>=integersOp2; --j)
		{
		sum=temp2[(nI-1)+(j-newOp2.posPoint+1)]+newOp2.bcd[j]+carry;
		temp2[(nI-1)+(j-newOp2.posPoint)+1]=sum%10;
		carry=sum/10;
		}

	for(i=nI-1; j>=0; --i,--j)
		{
		sum=temp2[i]+newOp2.bcd[j]+carry;
		temp2[i]=sum%10;
		carry=sum/10;
		}
	for(;i>=0; --i)
		{
		sum=temp2[i]+carry;
		temp2[i]=sum%10;
		carry=sum/10;
		}	

	bcd=temp2;
	posPoint=nI;
	this->normalize();
	return *this;
	}
else
	{
	int newSign, lastSign=sign;

	if(sign>0)
		newOp2.invertSign();
	else
		invertSign();

	if(*this==newOp2)
		{
		*this=floatBCD();
		return *this;
		}

	char digit1, digit2, carry=0;
	uintBCD temp2(newLength);
	fill(temp2,0);

	if(*this<newOp2)
		{
		if(lastSign>0)
			newSign=-1;
		else
			newSign=1;

		for(i=nI-1, j=integersOp2-1; j>=0; --i, --j)
			temp2[i]=newOp2.bcd[j];
		for(i=nI, j=integersOp2; j<newOp2.bcd.size(); ++i, ++j)
			temp2[i]=newOp2.bcd[j];
		for(j=bcd.size()-1; j>=integersOp1; --j)
			{
			digit1=temp2[(nI-1)+(j-posPoint+1)];
			digit2=bcd[j];
			digit1=digit1-carry;
			if(digit1<digit2)
				{
				carry=1;
				digit1+=10;
				}
			else
				{
				carry=0;
				}
			temp2[(nI-1)+(j-posPoint)+1]=digit1-digit2;
			}

		for(i=nI-1; j>=0; --i,--j)
			{
			digit1=temp2[i];
			digit2=bcd[j];
			digit1=digit1-carry;
			if(digit1<digit2)
				{
				carry=1;
				digit1+=10;
				}
			else
				{
				carry=0;
				}
			temp2[i]=digit1-digit2;
			}
		}
	else
		{
		if(lastSign>0)
			newSign=1;
		else
			newSign=-1;

		for(i=nI-1, j=integersOp1-1; j>=0; --i, --j)
			temp2[i]=bcd[j];
		for(i=nI, j=integersOp1; j<bcd.size(); ++i, ++j)
			temp2[i]=bcd[j];
		for(j=newOp2.bcd.size()-1; j>=integersOp2; --j)
			{
			digit1=temp2[(nI-1)+(j-newOp2.posPoint+1)];
			digit2=newOp2.bcd[j];
			digit1=digit1-carry;
			if(digit1<digit2)
				{
				carry=1;
				digit1+=10;
				}
			else
				{
				carry=0;
				}
			temp2[(nI-1)+(j-newOp2.posPoint)+1]=digit1-digit2;
			}

		for(i=nI-1; j>=0; --i,--j)
			{
			digit1=temp2[i];
			digit2=newOp2.bcd[j];
			digit1=digit1-carry;
			if(digit1<digit2)
				{
				carry=1;
				digit1+=10;
				}
			else
				{
				carry=0;
				}
			temp2[i]=digit1-digit2;
			}
		}
	for(;i>=0; --i)
		{
		digit1=temp2[i];
		digit1=digit1-carry;
		if(digit1<0)
			{
			carry=1;
			digit1+=10;
			}
		else
			{
			carry=0;
			}
		temp2[i]=digit1;
		}
	bcd=temp2;
	posPoint=nI;
	sign=newSign;
	normalize();
	return *this;
	}
}

inline floatBCD &floatBCD::operator-=(const floatBCD &op2)
{
*this+=(-op2);

return *this;
}

inline floatBCD &floatBCD::operator*=(const floatBCD &op2)
{
if(!sign)
	return *this;
if(!op2.sign)
	{
	*this=floatBCD();
	return *this;
	}

int newLength,i,j,k,l,nD, decimalsOp1, decimalsOp2;
char product, digit1, digit2, newDigit, carry=0, carry2=0;

decimalsOp1=bcd.size()-posPoint;
decimalsOp2=op2.bcd.size()-op2.posPoint;
nD=decimalsOp1+decimalsOp2;
newLength=bcd.size()+op2.bcd.size();
uintBCD temp(newLength);

for(i=0; i<temp.size(); ++i)
	temp[i]=0;

for(i=op2.bcd.size()-1, l=0; i>=0; --i, ++l)
	{
	carry=carry2=0;
	k=temp.size()-1-l;
	for(j=bcd.size()-1; j>=0; --j)
		{
		product=op2.bcd[i]*bcd[j]+carry;
		newDigit=(product)%10;
		carry=(product)/10;
		digit2=temp[k]+newDigit+carry2;
		carry2=digit2/10;
		newDigit=digit2%10;
		temp[k--]=newDigit;
		}
	for(; k>=0; --k)
		{
		digit1=temp[k]+carry+carry2;
		carry2=0;
		newDigit=digit1%10;
		carry=digit1/10;
		temp[k]=newDigit;
		}
	}

bcd=temp;
posPoint=newLength-nD;
exponent=exponent+op2.exponent;
if(sign+op2.sign)
	sign=1;
else
	sign=-1;
normalize();

return *this;
}

inline floatBCD &floatBCD::operator/=(const floatBCD &op2)
{

if(!(op2.sign))
	throw division_by_zero();
if((!sign))
	return *this;
if(*this==op2)
	{
	*this=floatBCD("1");
	return *this;
	}
if(op2==(floatBCD("1")))
	return *this;

floatBCD temp(op2);
doIntegerMantisa();
temp.doIntegerMantisa();

int nExp=exponent-temp.exponent;
int newSign;
newSign=(sign+temp.sign)? 1: -1;
uintBCD temp2, quotient;

int nAggregates=0, newPosPoint;

newPosPoint=bcd.size();

if(bcd.size()<temp.bcd.size())
	{
	nAggregates=temp.bcd.size()-bcd.size();
	bcd.resize(bcd.size()+nAggregates,0);
	}
while(bcd<temp.bcd)
 	{
	bcd.resize(bcd.size()+1,0);
	++nAggregates;
	}

uintBCD u1(bcd), u2(temp.bcd);

int i=0, lastPosition, pivot;

while(temp2<u2)
	temp2=u1.snippet(0,temp2.size()+1);
quotient.resize(temp2.size()-1,0);
	
pivot=temp2.size()-1;
lastPosition=u1.size()+precision;

do
	{
	i=0;

	while(temp2>=u2)
		{
		++i;
		temp2=temp2-u2;
		}

	quotient.resize(quotient.size()+1);
	quotient[quotient.size()-1]=i;

	do
		{
		++pivot;
		if(pivot<lastPosition)
			{
			temp2.resize(temp2.size()+1,0);
			if(pivot<u1.size())
				temp2[temp2.size()-1]=u1[pivot];
			else
				temp2[temp2.size()-1]=0;

			if(temp2<u2)
				{
				quotient.resize(quotient.size()+1);
				quotient[quotient.size()-1]=0;
				}
			else
				break;
			}
		else
			goto endDivision;
		}while(true);
	}while(true);

endDivision:

bcd=quotient;
posPoint=newPosPoint;
exponent=nExp;
sign=newSign;
normalize();

return *this;
}

inline floatBCD &floatBCD::operator^=(const floatBCD &op2)
{
if(!sign)
	return *this;

if(op2.isZero())
	{
	*this=floatBCD(true);
	return *this;
	}

if(op2.isPositive())
	{
	if(op2.isInteger())
		{
		floatBCD temp(1);
		for(floatBCD i; i<op2; ++i)
			temp*=*this;
		*this=temp;
		}
	else
		{
		floatBCD nth(10);//raíz a calcular, el número de decimales que tenga
		floatBCD n(op2);//potencia, la parte entera multiplicada por 10^nth
		floatBCD temp(*this);
		n.doIntegerMantisa();
		nth.exponent=abs(n.exponent);
		nth.enforceExp(0);
		n.exponent=0;

		temp^=n;
		temp=root(nth,temp);
		*this=temp;
		}
	}
else
	{
	if(op2.isInteger())
		{
		floatBCD temp(1);
		floatBCD inverse(op2);
		inverse.invertSign();
		for(floatBCD i; i<inverse; ++i)
			temp*=*this;

		temp=floatBCD(1)/temp;
		*this=temp;
		}
	else
		{
		floatBCD nth(10);//raíz a calcular, el número de decimales que tenga
		floatBCD n(op2);//potencia, la parte entera multiplicada por 10^nth
		floatBCD temp(*this);
		n.invertSign();
		n.doIntegerMantisa();
		nth.exponent=abs(n.exponent);
		nth.enforceExp(0);
		n.exponent=0;

		temp^=n;
		temp=root(nth,temp);
		temp=floatBCD(1)/temp;
		*this=temp;
		}
	}

return *this;
}

inline floatBCD &floatBCD::operator%=(const floatBCD &op2)
{
if(*this==op2)
	{
	*this=floatBCD(false);
	return *this;
	}
if(*this<op2)
	return *this;

floatBCD divisor(*this/op2);
*this-=op2*divisor.getIntegerPart();

//si la división es exacta, pero no se obtuvo como tal por truncamiento de decimales
if(*this==op2)
	*this=floatBCD(false);

return *this;
}

inline floatBCD floatBCD::operator+(const floatBCD &nBCD) const
{
if(!sign)
	return nBCD;
if(!nBCD.sign)
	return *this;
floatBCD temp(*this);
temp+=nBCD;

return temp;
}

inline floatBCD floatBCD::operator-(const floatBCD &op2) const
{
return (*this+(-op2));
}

inline floatBCD floatBCD::operator*(const floatBCD &op2) const
{
floatBCD temp(*this);
temp*=op2;

return temp;
}

inline floatBCD floatBCD::operator/(const floatBCD &op2) const
{
floatBCD temp(*this);
temp/=op2;

return temp;
}

//operador - monario
inline floatBCD floatBCD::operator-() const 
{
if(!sign)
	return (*this); 
floatBCD temp(*this);
temp.invertSign();

return temp;
}

inline floatBCD floatBCD::operator^(const floatBCD &op2) const
{
floatBCD temp(*this);
temp^=op2;

return temp;
}

inline floatBCD floatBCD::operator%(const floatBCD &op2) const
{
floatBCD temp(*this);
temp%=op2;

return temp;
}

inline floatBCD &floatBCD::operator++()
{
*this+=1;

return *this;
}

inline bool floatBCD::operator>(const floatBCD &op2) const
{
return !(*this<op2 || *this==op2);
}

inline bool floatBCD::operator<(const floatBCD &op2) const
{
int i;
if(!sign && !(op2.sign))
	return false;
if(!sign && (op2.sign>0))
	return true;
if(!sign && (op2.sign<0))
	return false;
if((sign>0) && (op2.sign<=0))
	return false;
if((sign<0) && (op2.sign>=0))
	return true;

floatBCD temp(op2);
	
temp.enforceExp(exponent);

if(sign>0)
	{
	if(posPoint>temp.posPoint)
		return false;
	if(posPoint<temp.posPoint)
		return true;

	for(i=0; i<posPoint; ++i)
		{
		if(bcd[i]>temp.bcd[i])
			return false;
		else if(bcd[i]<temp.bcd[i])
			return true;
		}
	int decimalsOp1=(bcd.size()-posPoint),
	decimalsOp2=(temp.bcd.size()-temp.posPoint);
	if(!(decimalsOp1+decimalsOp2))
		return false;
	int places=(decimalsOp1>decimalsOp2)? bcd.size(): temp.bcd.size();
	char digit1, digit2;
	for(; i<places; ++i)
		{
		digit1=(i>=bcd.size())? 0: bcd[i];
		digit2=(i>=temp.bcd.size())? 0: temp.bcd[i];
		if(digit1>digit2)
			return false;
		else if(digit1<digit2)
			return true;
		}
	}
else
	{
	if(posPoint>temp.posPoint)
		return true;
	if(posPoint<temp.posPoint)
		return false;
	for(i=0; i<posPoint; ++i)
		{
		if(bcd[i]>temp.bcd[i])
			return true;
		else if(bcd[i]<temp.bcd[i])
			return false;
		}
	int decimalsOp1=(bcd.size()-posPoint),
	decimalsOp2=(temp.bcd.size()-temp.posPoint);
	if(!(decimalsOp1+decimalsOp2))
		return false;
	int places=(decimalsOp1>decimalsOp2)? bcd.size(): temp.bcd.size();
	char digit1, digit2;
	for(; i<places; ++i)
		{
		digit1=(i>=bcd.size())? 0: bcd[i];
		digit2=(i>=temp.bcd.size())? 0: temp.bcd[i];
		if(digit1>digit2)
			return true;
		else if(digit1<digit2)
			return false;
		}
	}
return false;
}

inline bool floatBCD::operator>=(const floatBCD &op2) const
{
return !(*this<op2);
}

inline bool floatBCD::operator==(const floatBCD &op2) const
{
if((!sign) && (!op2.sign))
	return true;
if(!(sign+op2.sign))
	return false;

floatBCD temp(op2);
temp.enforceExp(exponent);

if((posPoint==temp.posPoint) && (bcd.size()==temp.bcd.size()))
	{
	for(int i=0; i<bcd.size(); ++i)
		{
		if(bcd[i]!=temp.bcd[i])
			return false;
		}
	return true;		
	}
else
	return false;
}

//multiplicación y división por 10
inline void floatBCD::mul10()
{
++exponent;
}

inline void floatBCD::div10()
{
--exponent;
}

inline void floatBCD::invertSign()
{
if(!sign)
	return;
if(sign>0)
	sign=-1;
else
	sign=1;
}

inline int floatBCD::size() const
{
return bcd.size();
}

inline bool floatBCD::isInteger() const
{
if(!sign)
	return false;
if(posPoint+exponent>=bcd.size())
	return true;
return false;
}

inline bool floatBCD::isFraction() const
{
if(!sign)
	return false;
if(posPoint+exponent>=bcd.size())
	return false;
return true;
}

inline bool floatBCD::isPositive() const
{
return (sign>0);
}

inline bool floatBCD::isNegative() const
{
return (sign<0);
}

inline bool floatBCD::isZero() const
{
return (sign==0);
}

inline int floatBCD::getSign() const
{
return sign;
}

inline int floatBCD::getExponent() const
{
return exponent;
}

inline floatBCD floatBCD::getIntegerPart() const
{
if(isFraction())
	{
	int realPosition=posPoint+exponent;

	if(realPosition<=0)
		return floatBCD();
	else
		{
		floatBCD temp;
		temp.bcd.resize(realPosition);
		copy(bcd.begin(),bcd.begin()+realPosition,temp.bcd.begin());
		temp.exponent=0;
		temp.posPoint=realPosition;
		temp.sign=sign;

		return temp;
		}
	}
else
	return *this;
}

ostream &operator<<(ostream &os, floatBCD nBCD)
{
if(!nBCD.sign)
	return (os<<'0');
if(nBCD.sign<0)
	os<<'-';

int i=0;

if(floatBCD::m_flags & floatBCD::sci)
	{
	if(!nBCD.posPoint)
		os<<'0';
	for(; i<nBCD.posPoint; ++i)
		os<<BCDAscii(nBCD.bcd[i]);
	if(i<nBCD.bcd.size())
		{
		os<<'.';
		for(; i<nBCD.bcd.size(); ++i)
			os<<BCDAscii(nBCD.bcd[i]);
		}
	if(nBCD.exponent)
		os<<'e'<<nBCD.exponent;

	return os;
	}

nBCD.doIntegerMantisa();

if(!nBCD.exponent)
	{
	for(; i<nBCD.bcd.size(); ++i)
		os<<BCDAscii(nBCD.bcd[i]);
	}
else if(nBCD.exponent<0)
	{
	int dif=nBCD.bcd.size()+nBCD.exponent;
	if(dif>0)
		{
		while(!nBCD.bcd[i] && i<dif)
			++i;
		if(i==dif)
			os<<"0.";
		else
			{
			for(; i<dif; ++i)
				{
				os<<BCDAscii(nBCD.bcd[i]);
				}
			os<<'.';
			}
		for(; i<nBCD.bcd.size(); ++i)
			os<<BCDAscii(nBCD.bcd[i]);
		}
	else if(dif==0)
		{
		os<<"0.";
		for(i=0; i<nBCD.bcd.size(); ++i)
			os<<BCDAscii(nBCD.bcd[i]);
		}
	else
		{
		os<<"0.";
		for(i=0; i>dif; --i)
			os<<'0';
		for(i=0; i<nBCD.bcd.size(); ++i)
			os<<BCDAscii(nBCD.bcd[i]);
		}
	}
else
	{
	for(i=0; i<nBCD.bcd.size(); ++i)
		os<<BCDAscii(nBCD.bcd[i]);
	for(i=0; i<nBCD.exponent; ++i)
		os<<'0';
	}

return os;
}

istream &operator>>(istream &is, floatBCD &nBCD)
{
static REEvaluator REEnospace="#*";
string s;
REEnospace.skipNoSymbols(is);
if(floatBCD::REEfloatBCD.getLexema(is,s))
	nBCD=floatBCD(s);

return is;
}

//Manipulators

ostream &fixed(ostream &os)
{
floatBCD r;
r.flags(floatBCD::fix);

return os;
}

ostream &scientific(ostream &os)
{
floatBCD r;
r.flags(floatBCD::sci);

return os;
}

floatBCD reduce(const floatBCD &n)
{

if(abs(n)<"6.283185308")
	return n;
else
	{
	floatBCD temp(abs(n));
	while(temp>"6.283185308")
		temp+=-(floatBCD("6.283185308"));
	if(n.isNegative())
		temp.invertSign();

	return temp;
	}
}

floatBCD fact(const floatBCD &n)
{
floatBCD temp(1), i(2);
for(; i<n || i==n; ++i)
	temp*=i;

return temp;
}

//e^x, utiliza la serie de maclaurin
floatBCD exp(const floatBCD &n)
{
floatBCD temp(1), i(2), limit(10);
temp+=n;

for(; i<limit; ++i)
	{
	temp+=(n^i)/fact(i);
	}

return temp;
}

floatBCD log(const floatBCD &n)
{
floatBCD temp;

return temp;
}

floatBCD ln(const floatBCD &n)
{
floatBCD temp;

return temp;
}

floatBCD sin(const floatBCD &n)
{
floatBCD newAngle(reduce(n)), temp(newAngle), i(3), limit(10*2);

bool s=false;
for(; i<limit; i+=2)
	{
	if(s)
		temp+=(newAngle^i)/fact(i);
	else
		temp+=-((newAngle^i)/fact(i));
	s=!s;
	}

return temp;
}

floatBCD sinh(const floatBCD &n)
{
floatBCD temp;

return temp;
}

floatBCD asin(const floatBCD &n)
{
floatBCD temp;

return temp;
}

floatBCD cos(const floatBCD &n)
{
floatBCD newAngle(reduce(n)), temp(1), i(2), limit(10*2);

bool s=false;
for(; i<limit; i+=2)
	{
	if(s)
		temp+=(newAngle^i)/fact(i);
	else
		temp+=-((newAngle^i)/fact(i));
	s=!s;
	}

return temp;
}

floatBCD cosh(const floatBCD &n)
{
floatBCD temp;

return temp;
}

floatBCD acos(const floatBCD &n)
{
floatBCD temp;

return temp;
}

floatBCD tan(const floatBCD &n)
{
floatBCD temp(sin(n)/cos(n));

return temp;
}

floatBCD tanh(const floatBCD &n)
{
floatBCD temp(sin(n)/cos(n));

return temp;
}

floatBCD atan(const floatBCD &n)
{
floatBCD temp(sin(n)/cos(n));

return temp;
}

floatBCD ctg(const floatBCD &n)
{
floatBCD temp(cos(n)/sin(n));

return temp;
}

floatBCD actg(const floatBCD &n)
{
floatBCD temp(sin(n)/cos(n));

return temp;
}

floatBCD sec(const floatBCD &n)
{
floatBCD temp(floatBCD(1)/cos(n));

return temp;
}

floatBCD asec(const floatBCD &n)
{
floatBCD temp(sin(n)/cos(n));

return temp;
}

floatBCD csc(const floatBCD &n)
{
floatBCD temp(floatBCD(1)/sin(n));

return temp;
}

floatBCD acsc(const floatBCD &n)
{
floatBCD temp(sin(n)/cos(n));

return temp;
}

floatBCD min1(const floatBCD &n1, const floatBCD &n2)
{
return (n1<n2? n1: n2);
}

floatBCD max1(const floatBCD &n1, const floatBCD &n2)
{
return (n1<n2? n2: n1);
}

floatBCD pow(const floatBCD &n, const floatBCD &nth)
{
return (n^nth);
}

floatBCD root(const floatBCD &nth, const floatBCD &n)
{
//return rootNewton(n,nth);
return rootGomezMorin(n,nth);
}

}

#endif