verylong.cpp

/*
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
*/
#include <iostream>
#include <cassert>
#include <cmath>
#include <string>
 
#include "verylong.h"
 
// Class Data
const Verylong Verylong::zero = Verylong("0");
const Verylong Verylong::one = Verylong("1");
const Verylong Verylong::two = Verylong("2");
 
 
// Constructors, Destructors and Conversion operators.
 
Verylong::Verylong(const std::string &value = "0")
{
	std::string s = (value == "") ? "0" : value;
 
	vlsign = (s[0] == '-') ? 1 : 0;        // check for negative sign
	if (ispunct(s[0]))                     // if the first character
		vlstr = s.substr(1, s.length() - 1); // is a punctuation mark.
	else 
		vlstr = s;
}
 
 
Verylong::Verylong(int n)
{
	if (n < 0)                           // check for sign and convert the
	{                                    // number to positive if it is negative
		vlsign = 1; 
		n = (-n); 
	} 
	else 
		vlsign = 0;                        
 
	if (n > 0)
	  while (n >= 1)                     // extract the number digit by digit and store 
	  {                                  // internally
		  vlstr = char(n % 10 + '0') + vlstr;
		  n /= 10;
	  }
	  else 
		  vlstr = std::string("0");          // else number is zero
}
 
 
Verylong::Verylong(const Verylong &x) : vlstr(x.vlstr), vlsign(x.vlsign) 
{ 
}
 
 
Verylong::~Verylong() 
{ 
}
 
 
Verylong::operator int() const
{
	int number, factor = 1;
	static Verylong max0(INT_MAX);
	static Verylong min0(INT_MIN + 1);
	std::string::const_reverse_iterator j = vlstr.rbegin();
 
	if (*this > max0)
	{
		std::cerr << "Error : Conversion Verylong->integer is not possible" << std::endl;
		return INT_MAX;
	}
	else 
	if (*this < min0)
	{
		std::cerr << "Error : Conversion Verylong->integer is not possible" << std::endl;
		return INT_MIN;
	}
 
	number = *j - '0';
 
	for (j++; j != vlstr.rend(); j++)
	{
		factor *= 10;
		number += (*j - '0') * factor;
	}
 
	if (vlsign) 
		return -number;
 
	return number;
}
 
 
Verylong::operator double() const
{
	double sum, factor = 1.0;
	std::string::const_reverse_iterator i = vlstr.rbegin();
 
	sum = double(*i) - '0';
 
	for (i++; i != vlstr.rend(); i++)
	{
		factor *= 10.0;
		sum += double(*i - '0') * factor;
	}
 
	if (vlsign) 
		return -sum;
 
	return sum;
}
 
 
Verylong::operator std::string() const
{
	if (vlstr.length() == 0) 
		return std::string("0");
 
	return vlstr;
}
 
 
 
// Various member operators
 
const Verylong & Verylong::operator = (const Verylong &rhs)
{
	if (this == &rhs) 
		return *this;
 
	vlstr = rhs.vlstr;
	vlsign = rhs.vlsign;
 
	return *this;
}
 
 
// Unary - operator
Verylong Verylong::operator -() const
{
	Verylong temp(*this);
 
	if (temp != zero)  
		temp.vlsign = !vlsign;
 
	return temp;
}
 
 
// Prefix increment operator
Verylong Verylong::operator ++ ()
{
	return *this = *this + one;
}
 
 
// Postfix increment operator
Verylong Verylong::operator ++ (int)
{
	Verylong result(*this);
 
	*this = *this + one;
	return result;
}
 
 
// Prefix decrement operator
Verylong Verylong::operator -- ()
{
	return *this = *this - one;
}
 
 
// Postfix decrement operator
Verylong Verylong::operator -- (int)
{
	Verylong result(*this);
 
	*this = *this - one;
	return result;
}
 
 
Verylong Verylong::operator += (const Verylong &v)
{
	return *this = *this + v;
}
 
 
Verylong Verylong::operator -= (const Verylong &v)
{
	return *this = *this - v;
}
 
 
Verylong Verylong::operator *= (const Verylong &v)
{
	return *this = *this * v;
}
 
 
Verylong Verylong::operator /= (const Verylong &v)
{
	return *this = *this / v;
}
 
 
Verylong Verylong::operator %= (const Verylong &v)
{
	return *this = *this % v;
}
 
 
Verylong Verylong::operator ^= (const Verylong &degree)
{
	Verylong N(degree);
	Verylong Y("1");
 
	if (N == Verylong::zero)
		return Verylong::one;
 
	if (N < Verylong::zero)
		return Verylong::zero;
 
	while (1)
	{
		if (N == Verylong::zero)
		{
			*this = Y;
			break;
		}
 
		Y = Y * *this;
		N = N - Verylong::one;
	}
 
	return *this;
}
 
 
 
// Various friendship operators and functions.
 
Verylong operator + (const Verylong &u, const Verylong &v)
{
	char digitsum, d1, d2, carry = 0;
	std::string temp;
	std::string::const_reverse_iterator j, k;
 
	if (u.vlsign ^ v.vlsign)
	{
		if (u.vlsign == 0) 
			return u - abs(v);
		else               
			return v - abs(u);
	}
 
	for (j = u.vlstr.rbegin(), k = v.vlstr.rbegin();
		j != u.vlstr.rend() || k != v.vlstr.rend();)
	{
		d1 = (j == u.vlstr.rend()) ? 0 : *(j++) - '0'; // get digit
		d2 = (k == v.vlstr.rend()) ? 0 : *(k++) - '0'; // get digit
		digitsum = d1 + d2 + carry;                    // add digits
 
		carry = (digitsum >= 10) ? 1 : 0;
		digitsum -= 10 * carry;
 
		temp = char(digitsum + '0') + temp;
	}
 
	if (carry) // if carry at end, last digit is 1
		temp = '1' + temp;  
 
	if (u.vlsign) 
		temp = '-' + temp;
 
	return Verylong(temp);
}
 
 
Verylong operator - (const Verylong &u, const Verylong &v)
{
	char d, d1, d2, borrow = 0;
	int negative;
	std::string temp, temp2;
	std::string::reverse_iterator i, j;
 
	if (u.vlsign ^ v.vlsign)
	{
		if (u.vlsign == 0) 
			return u + abs(v);
		else
			return -(v + abs(u));
	}
 
	Verylong w, y;
 
	if (u.vlsign == 0)                   // both u,v are positive
		if (u<v) 
		{ 
			w = v; 
			y = u; 
			negative = 1; 
		}
		else    
		{ 
			w = u; 
			y = v; 
			negative = 0; 
		}
		else                               // both u,v are negative
		if (u<v) 
		{ 
			w = u; 
			y = v; 
			negative = 1; 
		}
		else    
		{ 
			w = v; 
			y = u; 
			negative = 0; 
		}
 
	for (i = w.vlstr.rbegin(), j = y.vlstr.rbegin();
		i != w.vlstr.rend() || j != y.vlstr.rend();)
	{
		d1 = (i == w.vlstr.rend()) ? 0 : *(i++) - '0';
		d2 = (j == y.vlstr.rend()) ? 0 : *(j++) - '0';
 
		d = d1 - d2 - borrow;
		borrow = (d < 0) ? 1 : 0;
		d += 10 * borrow;
 
		temp = char(d + '0') + temp;
	}
 
	while (temp[0] == '0') 
		temp = temp.substr(1);
 
	if (negative) 
		temp = '-' + temp;
 
	return Verylong(temp);
}
 
 
Verylong operator * (const Verylong &u, const Verylong &v)
{
	Verylong pprod("1"), tempsum("0");
	std::string::const_reverse_iterator r = v.vlstr.rbegin();
 
	for (int j = 0; r != v.vlstr.rend(); j++, r++)
	{
		int digit = *r - '0';              // extract a digit
 
		pprod = u.multdigit(digit);        // multiplied by the digit
		pprod = pprod.mult10(j);           // "adds" suitable zeros behind
		tempsum = tempsum + pprod;         // result added to tempsum
	}
 
	tempsum.vlsign = u.vlsign^v.vlsign;  // to determine sign
	return tempsum;
}
 
 
//  This algorithm is the long division algorithm.
Verylong operator / (const Verylong &u, const Verylong &v)
{
	int len = u.vlstr.length() - v.vlstr.length();
	std::string temp;
	Verylong w, y, b, c, d, quotient = Verylong::zero;
 
	if (v == Verylong::zero)
	{
		std::cerr << "Error : division by zero" << std::endl;
		return Verylong::zero;
	}
 
	w = abs(u); 
	y = abs(v);
 
	if (w < y) 
		return Verylong::zero;
 
	c = Verylong(w.vlstr.substr(0, w.vlstr.length() - len));
 
	for (int i = 0; i <= len; i++)
	{
		quotient = quotient.mult10(1);
 
		b = d = Verylong::zero;            // initialize b and d to 0
 
		while (b < c)
		{
			b = b + y; d = d + Verylong::one;
		}
 
		if (c < b)                           // if b>c, then
		{                                    // we have added one count too many 
			b = b - y;
			d = d - Verylong::one;
		}
 
		quotient = quotient + d;             // add to the quotient
 
		if (i < len)
		{
			// partial remainder * 10 and add to next digit
			c = (c - b).mult10(1);
			c += Verylong(w.vlstr[w.vlstr.length() - len + i] - '0');
		}
	}
 
	quotient.vlsign = u.vlsign^v.vlsign;   // to determine sign
 
	return quotient;
}
 
 
Verylong operator % (const Verylong &u, const Verylong &v)
{
	return (u - v*(u / v));
}
 
 
Verylong operator ^ (const Verylong &u, const Verylong &v)
{
	//return (u - v*(u / v));
 
	Verylong temp(u);
 
	return temp ^= v;
}
 
 
 
int operator == (const Verylong &u, const Verylong &v)
{
	return (u.vlsign == v.vlsign && u.vlstr == v.vlstr);
}
 
 
int operator != (const Verylong &u, const Verylong &v)
{
	return !(u == v);
}
 
 
int operator < (const Verylong &u, const Verylong &v)
{
	if (u.vlsign < v.vlsign) 
		return 0;
	else 
	if (u.vlsign > v.vlsign) 
		return 1;
 
	// exclusive or (^) to determine sign
	if (u.vlstr.length() < v.vlstr.length()) 
		return (1 ^ u.vlsign);
	else 
	if (u.vlstr.length() > v.vlstr.length()) 
		return (0 ^ u.vlsign);
 
	return (u.vlstr < v.vlstr && !u.vlsign) ||
		(u.vlstr > v.vlstr && u.vlsign);
}
 
 
int operator <= (const Verylong &u, const Verylong &v)
{
	return (u<v || u == v);
}
 
 
int operator >(const Verylong &u, const Verylong &v)
{
	return (!(u<v) && u != v);
}
 
 
int operator >= (const Verylong &u, const Verylong &v)
{
	return (u>v || u == v);
}
 
 
// Calculate the absolute value of a number
Verylong abs(const Verylong &v)
{
	Verylong u(v);
 
	if (u.vlsign) 
		u.vlsign = 0;
 
	return u;
}
 
// Calculate the integer square root of a number
//    based on the formula (a+b)^2 = a^2 + 2ab + b^2
Verylong sqrt(const Verylong &v)
{
	// if v is negative, error is reported
	if (v.vlsign) 
	{ 
		std::cerr << "NaN" << std::endl; 
		return Verylong::zero; 
	}
 
	int j, k = v.vlstr.length() + 1, num = k >> 1;
	Verylong y, z, sum, tempsum, digitsum;
 
	std::string temp, w(v.vlstr);
 
	k = 0;
	j = 1;
 
	// segment the number 2 digits by 2 digits
	if (v.vlstr.length() % 2) 
		digitsum = Verylong(w[k++] - '0');
	else
	{
		digitsum = Verylong((w[k] - '0') * 10 + w[k + 1] - '0');
		k += 2;
	}
 
	// find the first digit of the integer square root
	sum = z = Verylong(int(sqrt(double(digitsum))));
 
	// store partial result
	temp = char(int(z) + '0');
	digitsum = digitsum - z*z;
 
	for (; j<num; j++)
	{
		// get next digit from the number
		digitsum = digitsum.mult10(1) + Verylong(w[k++] - '0');
		y = z + z;        // 2*a
		z = digitsum / y;
		tempsum = digitsum.mult10(1) + Verylong(w[k++] - '0');
		digitsum = -y*z.mult10(1) + tempsum - z*z;
 
		// decrease z by 1 and re-calculate when it is over-estimated.
		while (digitsum < Verylong::zero)
		{
			--z;
			digitsum = -y*z.mult10(1) + tempsum - z*z;
		}
 
		temp = temp + char(int(z) + '0');  // store partial result
		z = sum = sum.mult10(1) + z;       // update value of the partial result
	}
 
	Verylong result(temp);
 
	return result;
}
 
 
// Raise a number X to a power of degree
Verylong pow(const Verylong &X, const Verylong &degree)
{
	Verylong N(degree), Y("1"), x(X);
 
	if (N == Verylong::zero) 
		return Verylong::one;
 
	if (N < Verylong::zero) 
		return Verylong::zero;
 
	while (1)
	{
		if (N%Verylong::two != Verylong::zero)
		{
			Y = Y * x;
			N = N / Verylong::two;
			if (N == Verylong::zero) 
				return Y;
		}
		else  
			N = N / Verylong::two;
 
		x = x * x;
	}
}
 
 
// Double division function
double div(const Verylong &u, const Verylong &v)
{
	double qq = 0.0, qqscale = 1.0;
	Verylong w, y, b, c;
	int d, count,
		decno = std::numeric_limits<double>::digits; // number of significant digits
 
	if (v == Verylong::zero)
	{
		std::cerr << "ERROR : Division by zero" << std::endl;
		return 0.0;
	}
 
	if (u == Verylong::zero) 
		return 0.0;
 
	w = abs(u); 
	y = abs(v);
 
	while (w<y) 
	{ 
		w = w.mult10(1); 
		qqscale *= 0.1; 
	}
 
	int len = w.vlstr.length() - y.vlstr.length();
	std::string temp = w.vlstr.substr(0, w.vlstr.length() - len);
 
	c = Verylong(temp);
 
	for (int i = 0; i <= len; i++)
	{
		qq *= 10.0;
 
		b = Verylong::zero; d = 0;         // initialize b and d to 0
 
		while (b < c)
		{
			b += y; d += 1;
		}
 
		if (c < b)                         // if b>c, then
		{                                  // we have added one count too many
			b -= y; 
			d -= 1;
		}                                
 
		qq += double(d);                   // add to the quotient
 
		c = (c - b).mult10(1);             // the partial remainder * 10
 
		if (i < len)                       // and add to next digit
			c += Verylong(w.vlstr[w.vlstr.length() - len + i] - '0');
	}
 
	qq *= qqscale; count = 0;
 
	while (c != Verylong::zero && count < decno)
	{
		qqscale *= 0.1;
 
		b = Verylong::zero; d = 0;         // initialize b and d to 0
 
		while (b < c)
		{
			b += y; d += 1;
		}
 
		if (c < b)                         // if b>c, then
		{                                  // we have added one count too many
			b -= y; d -= 1;
		}           
 
		qq += double(d)*qqscale;
 
		c = (c - b).mult10(1);
		count++;
	}
 
	if (u.vlsign^v.vlsign)               // check for the sign
		qq *= (-1.0); 
 
	return qq;
}
 
 
std::ostream & operator << (std::ostream &s, const Verylong &v)
{
	if (v.vlstr.length() > 0)
	{
		if (v.vlsign) s << "-";
		s << v.vlstr;
	}
	else 
		s << "0";
 
	return s;
}
 
 
std::istream & operator >> (std::istream &s, Verylong &v)
{
	std::string temp(10000, ' ');
 
	s >> temp;
	v = Verylong(temp);
 
	return s;
}
 
 
//
// Private member functions: multdigit(), mult10().
//
 
// Multiply this Verylong number by num
Verylong Verylong::multdigit(int num) const
{
	int carry = 0;
	std::string::const_reverse_iterator r;
 
	if (num)
	{
		std::string temp;
 
		for (r = vlstr.rbegin(); r != vlstr.rend(); r++)
		{
			int d1 = *r - '0',               // get digit and multiplied by
				digitprod = d1*num + carry;    // that digit plus carry
 
			if (digitprod >= 10)             // if there's a new carry,
			{
				carry = digitprod / 10;        // carry is high digit
				digitprod -= carry * 10;       // result is low digit
			}
			else 
				carry = 0;                     // otherwise carry is 0
 
			temp = char(digitprod + '0') + temp;   // insert char in string
		}
 
		if (carry) //if carry at end,
			temp = char(carry + '0') + temp; 
 
		Verylong result(temp);
		return result;
	}
	else 
		return zero;
}
 
 
// Multiply this Verylong number by 10*num
Verylong Verylong::mult10(int num) const
{
	int j;
 
	if (*this != zero)
	{
		std::string temp;
 
		for (j = 0; j<num; j++) 
			temp = temp + '0';
 
		Verylong result(vlstr + temp);
 
		if (vlsign) 
			result = -result;
 
		return result;
	}
	else 
		return zero;
}
 
 
//template <> Verylong zero(Verylong) { return Verylong::zero; }
//template <> Verylong one(Verylong) { return Verylong::one; }