#include <iostream>
#include <ctype.h>
#include <limits.h>
#include <fstream>
#include <vector>
#include <string>
#include <strstream>
#include "BigInt.h"

#include "BigFloat.h"

using namespace std;

// Author: Sean Colombo
// Date:   10/3/2003

BigFloat::BigFloat():
myDigs(), myPrecision(0){
}

BigFloat::BigFloat(int num):
myDigs(num), myPrecision(0){
}

BigFloat::BigFloat(float num):
myDigs(), myPrecision(0){
	strstream theStream;
	string theString;

	theStream<<num;
	theStream>>theString;

	BigFloat tempFloat(theString);
	myDigs = tempFloat.myDigs;
	myPrecision = tempFloat.myPrecision;
}

BigFloat::BigFloat(double num):
myDigs(), myPrecision(0){
	strstream theStream;
	string theString;

	theStream<<num;
	theStream>>theString;

	BigFloat tempFloat(theString);
	myDigs = tempFloat.myDigs;
	myPrecision = tempFloat.myPrecision;
}

BigFloat::BigFloat(BigInt num):
myDigs(num), myPrecision(0){
}

BigFloat::BigFloat(const string & s):
myDigs(), myPrecision(0){
	string tempStr;

	
	if(s.find('.')==-1){
		myDigs = (BigInt)s;
	} else {
		tempStr = s.substr(0,s.find('.'));
		tempStr+= s.substr(s.find('.')+1);
		myDigs = (BigInt)tempStr;
		tempStr = s;
		while((tempStr[0]=='0')||(tempStr[0]=='+')||(tempStr[0]=='-')){
			tempStr = tempStr.substr(1);
		}
		myPrecision = (tempStr.length() - tempStr.find('.') - 1);
	}
}

BigFloat::BigFloat(const BigFloat &rhs):
myDigs(rhs.myDigs), myPrecision(rhs.myPrecision){
}

const BigFloat & BigFloat::operator = (const BigFloat & rhs){
	myDigs = rhs.myDigs;
	myPrecision = rhs.myPrecision;

	return *this;
}

BigFloat::~BigFloat(){}

BigFloat BigFloat::add(BigFloat &rhs){
	BigFloat retVal;

	while(myPrecision<rhs.myPrecision){
		myDigs*=10;
		myPrecision++;
	}
	while(rhs.myPrecision<myPrecision){
		rhs.myDigs = (rhs.myDigs*10);
		rhs.myPrecision = (rhs.myPrecision+1);
	}

	retVal.myDigs = (myDigs + rhs.myDigs);
	retVal.myPrecision = (myPrecision);

	return retVal;
}

BigFloat BigFloat::sub(BigFloat &rhs){
	BigFloat retVal;

	while(myPrecision<rhs.myPrecision){
		myDigs*=10;
		myPrecision++;
	}
	while(rhs.myPrecision<myPrecision){
		rhs.myDigs = (rhs.myDigs*10);
		rhs.myPrecision = (rhs.myPrecision+1);
	}

	retVal.myDigs = (myDigs - rhs.myDigs);
	retVal.myPrecision = (myPrecision);

	return retVal;
}

BigFloat BigFloat::mul(BigFloat &rhs){
	BigFloat retVal;

	retVal.myDigs = (myDigs * rhs.myDigs);
	retVal.myPrecision = (myPrecision + rhs.myPrecision);

	return retVal;
}

BigFloat BigFloat::div(BigFloat &rhs, int precision){
	BigFloat retVal;
	BigFloat num = (*this);
	BigFloat den = rhs;

	while(num.myPrecision<den.myPrecision){
		num.myDigs*=10;
		num.myPrecision++;
	}
	while(den.myPrecision<num.myPrecision){
		den.myDigs = (den.myDigs*10);
		den.myPrecision = (den.myPrecision+1);
	}

	num.myDigs = ( num.myDigs * ((BigInt)10^((BigInt)precision)));
	retVal.myDigs = (num.myDigs / den.myDigs);
	retVal.myPrecision = (precision);

	retVal.Normalize();
	return retVal;
}

BigFloat BigFloat::neg(){
	return (myDigs*-1);
}

BigFloat BigFloat::abs(){
	if(myDigs<0){
		return neg();
	} else {
		return myDigs;
	}
}

void BigFloat::round(int precision){
	while(precision>myDigs.myNumDigits){
		myDigs*=10;
		precision++;
	}
	myPrecision = precision;
}

BigInt BigFloat::getDigs() const{
	return myDigs;
}

int BigFloat::getPrecision() const{
	return myPrecision;
}

ostream & operator <<(ostream & out, const BigFloat & big){
	string outStr;
	string num;

	num = ((BigInt)big.getDigs()).ToString();
	outStr = num.substr(0, (num.length()-big.getPrecision()));
	if(big.getPrecision() > 0){
		outStr += '.';
	}
	outStr+= num.substr(num.length()-big.getPrecision());
	if(big.getPrecision()==num.length()){
		outStr = "0" + outStr;
	}

	out << outStr;
	return out;
}

istream & operator >> (istream & in, BigFloat & big){
    string tempStr;
	
    in >> tempStr;
    big = BigFloat(tempStr);
    return in;
}

void BigFloat::Normalize(){
    BigInt head;
	BigInt tail;
	string tempStr = myDigs.ToString();
	int diff;

	tail = tempStr.substr(tempStr.length()-myPrecision);
	head = tempStr.substr(0,(tempStr.length()-myPrecision));
	if(tail!=0){
		while((tail%10)==0){
			tail/=10;
		}
	}

	tempStr = head.ToString();
	if(tail!=0){
		tempStr+= tail.ToString();
	}

	diff = myDigs.myNumDigits;
	myDigs = tempStr;
	diff = diff - myDigs.myNumDigits;
	myPrecision -= diff;
}


bool operator == (const BigFloat & lhs, const BigFloat & rhs){
	return lhs.Equal(rhs);
}

bool BigFloat::Equal(const BigFloat & rhs) const{
	BigFloat right = rhs;
	BigFloat left = (*this);
	left.Normalize();
	right.Normalize();
	return ((left.myDigs == right.myDigs)&&(left.myPrecision == right.myPrecision));
}

bool operator != (const BigFloat & lhs, const BigFloat & rhs){
	return !(lhs == rhs);
}

bool operator < (const BigFloat & lhs, const BigFloat & rhs){
	return (lhs.LessThan(rhs));
}

bool BigFloat::LessThan(const BigFloat & rhs) const{
	BigInt headL;
	BigInt tailL;
	BigInt headR;
	BigInt tailR;
	BigFloat left = (*this);
	BigFloat right = rhs;
	string tempStr;
	left.Normalize();
	right.Normalize();
	tempStr = left.myDigs.ToString();
	headL = tempStr.substr(0,(tempStr.length()-left.myPrecision));
	tailL = tempStr.substr(tempStr.length()-left.myPrecision);
	tempStr = right.myDigs.ToString();
	headR = tempStr.substr(0,(tempStr.length()-right.myPrecision));
	tailR = tempStr.substr(tempStr.length()-right.myPrecision);

	return ((headL<headR)||((headL==headR)&&(tailL<tailR)));
}

bool operator > (const BigFloat & lhs, const BigFloat & rhs){
	return (rhs < lhs);
}

bool operator <= (const BigFloat & lhs, const BigFloat & rhs){
    return ((lhs == rhs) || (lhs < rhs));
}

bool operator >= (const BigFloat & lhs, const BigFloat & rhs){
    return ((lhs == rhs) || (lhs > rhs));
}
