大整数类的实现

      昨天有点空闲,一晚上写了一个大整数类。所谓大整数即是无限长整数,如200!即是使用long long或__int64也无法存储,这就需要使用大整数来保存。

      写这个大整数类有两个目的,第一是为了复习一下C++的基本思想,第二是今后若有项目可以用到则有基础。但是昨晚为了赶工,有些算法没有优化,类的设计也不是很合理,而且在代码编写过程中还是有一些问题困扰着我。下面将代码贴出,请各位走过路过的大牛提提建议,批评指正。

      大整数类BigInt使用字符串存储整数,如整数1000则保存为"1000"。

      头文件BigInt.h如下,其中自定义了一个异常类,用于防止使用非法字符串来初始化整数,如"1dfaf"等。

/*******************************************
* 大整数类BigInt
* 功能:存储无限长整数
* 作者:万户侯(billsedison)
* 日期:2010.12.24
* 版本:1.0
*******************************************/
// BigInt.h
#ifndef _BIG_INT_
#define _BIG_INT_


// g++不通过,由于BigInt&与BigInt的区别,以后需要再研究
// 为何const BigInt&作为BigInt::IsLegal的参数会通不过编译?
// VC6,VS2010通过

#include <iostream>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <fstream>

using namespace std; // 这里为了赶工,就在头文件里引入了命名空间std,以后需要做调整

// 自定义异常类,考虑BigInt是否合法
class bigint_error : public runtime_error
{
public:
	bigint_error(const string& msg = "") : runtime_error(msg)
	{
	}
};

// 定义负号
#define MINUS_SYMBOL '-'

// 定义宏,将字符转为对应的数字
#define CHAR_TO_INT(x) ((x) - 0x30)

// 定义宏,将对应的数字转为字符
#define INT_TO_CHAR(x) ((char)((x) + 0x30))

// VC6 bug
// 重载操作符需要在类外声明
class BigInt;
// 比较运算 >
bool operator > (BigInt& b1, BigInt& b2);
// 比较运算 >=
bool operator >= (BigInt& b1, BigInt& b2);
// 比较运算 <
bool operator < (BigInt& b1, BigInt& b2);
// 比较运算 <=
bool operator <= (BigInt& b1, BigInt& b2);
// 比较运算 ==
bool operator == (BigInt& b1, BigInt& b2);
// 比较运算 !=
bool operator != (BigInt& b1, BigInt& b2);
// 输出
ostream& operator << (ostream& os, BigInt& b);	
// 友元函数,大整数类加法
BigInt operator + (BigInt& b1, BigInt& b2);
// 友元函数,大整数类减法
BigInt operator - (BigInt& b1, BigInt& b2);
// 友元函数,大整数类乘法
BigInt operator * (BigInt& b1, BigInt& b2);
// 友元函数,大整数类除法
BigInt operator / (BigInt& b1, BigInt& b2);
// 友元函数,大整数类取余
BigInt operator % (BigInt& b1, BigInt& b2);

// 大整数类
class BigInt
{
private:
	string m_strInt; // 使用字符串来保存整数
	static const string m_cstrLegalChar; // 保存合法字符
public:
	// Constructor/Destructor
	// 构造函数
	BigInt(const string& str = "0"); // 初始化为0
	BigInt(const char* pstr); // 初始化为0
	// 拷贝构造函数
	BigInt(BigInt& b);
public:
	// getter/setter
	const string& GetStrInt()
	{
		return m_strInt;
	}
public:
	// Attributes
	// 判断大整数是否合法
	bool IsLegal(); 
	// 若为0,消除负号,否则返回原样
	BigInt& DelZeroNeg();
private:
	// 正数加法(纯正数加法,不考虑负号)
	BigInt Add(BigInt& b);
	// 正数减法(纯正数减法,不考虑负号)
	BigInt Sub(BigInt& b);
	// 正数乘法(纯正数乘法,不考虑负号)
	BigInt Mul(BigInt& b);
	// 正数除法(纯正数除法,不考虑负号)
	BigInt Div(BigInt& b);
	// 正数取余(纯正数取余,不考虑负号)
	BigInt Mod(BigInt& b);
	// 正数比较,返回值> 0 则>,< 0 则小, == 0则相等
	int Cmp(BigInt& b);
	// 是否为0,消除0与-0的差别
	bool IsZero();	
public:
	// 成员operator
	// 取负
	BigInt operator - ();
	// 赋值
	BigInt& operator = (BigInt& b);
	// 赋值
	BigInt& operator = (const string& b);
	// 自增
	BigInt& operator ++ ();
	// 自增,后置
	BigInt operator ++ (int);
	// 自减
	BigInt& operator -- ();
	// 自减,后置
	BigInt operator -- (int);
	// 赋值 +=
	BigInt& operator += (BigInt& b);
	// 赋值 -=
	BigInt& operator -= (BigInt& b);
	// 赋值 *=
	BigInt& operator *= (BigInt& b);
	// 赋值 /=
	BigInt& operator /= (BigInt& b);
	// 赋值 %=
	BigInt& operator %= (BigInt& b);
public:
	// 友元operator	
	// 比较运算 >
	friend bool operator > (BigInt& b1, BigInt& b2);
	// 比较运算 >=
	friend bool operator >= (BigInt& b1, BigInt& b2);
	// 比较运算 <
	friend bool operator < (BigInt& b1, BigInt& b2);
	// 比较运算 <=
	friend bool operator <= (BigInt& b1, BigInt& b2);
	// 比较运算 ==
	friend bool operator == (BigInt& b1, BigInt& b2);
	// 比较运算 !=
	friend bool operator != (BigInt& b1, BigInt& b2);
	// 输出
	friend ostream& operator << (ostream& os, BigInt& b);	
	// 友元函数,大整数类加法
	friend BigInt operator + (BigInt& b1, BigInt& b2);
	// 友元函数,大整数类减法
	friend BigInt operator - (BigInt& b1, BigInt& b2);
	// 友元函数,大整数类乘法
	friend BigInt operator * (BigInt& b1, BigInt& b2);
	// 友元函数,大整数类除法
	friend BigInt operator / (BigInt& b1, BigInt& b2);
	// 友元函数,大整数类取余
	friend BigInt operator % (BigInt& b1, BigInt& b2);
};

#endif


        头文件中,定义了大整数类的属性与方法,其中使用了大量运算符重载,使得BigInt的使用与一般整数如int的使用方法类似,下面给出类的实现文件代码BigInt.cpp,代码如下:

// BigInt.cpp
#include "BigInt.h"

// 保存合法字符
const string BigInt::m_cstrLegalChar = "0123456789-";

// 构造函数
BigInt::BigInt(const string& str) : m_strInt(str)
{
	// 若为空字符串
	if (m_strInt.empty())
	{
		m_strInt = "0"; // 初始化为0
	}
	else // 不为空
	{
		if (!IsLegal()) // 如果不合法
		{
			throw bigint_error("初始化含有非法字符");
		}
		DelZeroNeg();
	}
}

BigInt::BigInt(const char* pstr) :m_strInt(pstr)
{
	// 若为空字符串
	if (m_strInt.empty())
	{
		m_strInt = "0"; // 初始化为0
	}
	else // 不为空
	{
		if (!IsLegal()) // 如果不合法
		{
			throw bigint_error("初始化含有非法字符");
		}
		DelZeroNeg();
	}
}

// 拷贝构造函数
BigInt::BigInt(BigInt& b)
{
	operator = (b);
}

// 判断大整数是否合法
bool BigInt::IsLegal()
{
	bool bRet;
	// 对于个位数
	if (m_strInt.length() == 1)
	{
		// 判断是否含有除负号之外的所有字符
		// 若找到其他字符,则返回false
		return !(m_strInt.find_first_not_of(m_cstrLegalChar.substr(0, m_cstrLegalChar.length() - 1)) != string::npos);
	}
	else // 对于多位数
	{
		bRet = true;
		// 判断第一位,可含符号位
		bRet &= (m_cstrLegalChar.find(m_strInt.at(0)) != string::npos);
		// 判断余下位数
		bRet &= !(m_strInt.substr(1).find_first_not_of(m_cstrLegalChar.substr(0, m_cstrLegalChar.length() - 1)) != string::npos);
		return bRet;
	}
}

// 正数加法(纯正数加法,不考虑负号)
BigInt BigInt::Add(BigInt& b)
{
	string strResult; // 保存结果的字符串
	int i = m_strInt.length() - 1, j = b.GetStrInt().length() - 1;
	int fstNum, sndNum; // 第一个,第二个个位数
	int sum; // 每一次加法的和
	int carry = 0; // 保存进位
	while (i >= 0 && j >= 0) // 从后往前加法
	{
		// 从后往前加法,将每一位转成对应的数字
		fstNum = CHAR_TO_INT(m_strInt.at(i));
		sndNum = CHAR_TO_INT(b.GetStrInt().at(j));
		sum = fstNum + sndNum + carry;		
		// 处理进位
		if (sum >= 10)
		{			
			carry = sum / 10;
			sum %= 10;
		}
		else
		{			
			carry = 0;
		}
		strResult.append(string(1, INT_TO_CHAR(sum))); // 先顺序加
		i--;
		j--;
	}

	// 处理剩余部分		
	while (i >= 0)
	{
		if (carry != 0)
		{
			sum = CHAR_TO_INT(m_strInt.at(i)) + carry;
			// 处理进位
			if (sum >= 10)
			{			
				carry = sum / 10;
				sum %= 10;
			}
			else
			{			
				carry = 0;
			}
			strResult.append(string(1, INT_TO_CHAR(sum))); // 先顺序加
		}
		else
		{
			strResult.append(string(1, m_strInt.at(i)));
		}
		i--;
	}

	
	while (j >= 0)
	{
		if (carry != 0)
		{
			sum = CHAR_TO_INT(b.GetStrInt().at(j)) + carry;
			// 处理进位
			if (sum >= 10)
			{			
				carry = sum / 10;
				sum %= 10;
			}
			else
			{			
				carry = 0;
			}
			strResult.append(string(1, INT_TO_CHAR(sum))); // 先顺序加
		}
		else
		{
			strResult.append(string(1, b.GetStrInt().at(j)));
		}
		j--;
	}

	if (carry != 0) // 若此时进位还不为0
	{
		strResult.append(string(1, INT_TO_CHAR(carry))); // 先顺序加
	}

	// 反转结果
	reverse(strResult.begin(), strResult.end());
	return BigInt(strResult).DelZeroNeg();
}

// 正数减法(纯正数减法,不考虑负号)
BigInt BigInt::Sub(BigInt& b)
{
	int nCmp = Cmp(b);
	if (nCmp == 0) // 如果二者相等
	{
		return BigInt("0");
	}
	string strResult; // 保存结果的字符串
	int i = m_strInt.length() - 1, j = b.GetStrInt().length() - 1;
	int fstNum, sndNum; // 第一个,第二个个位数,第一个为较大数
	int diff; // 每一次减法的差
	int carry = 0; // 保存进位
	while (i >= 0 && j >= 0) // 从后往前减法
	{
		// 从后往前加法,将每一位转成对应的数字
		if (nCmp > 0)
		{
			fstNum = CHAR_TO_INT(m_strInt.at(i));
			sndNum = CHAR_TO_INT(b.GetStrInt().at(j));
		}
		else
		{
			sndNum = CHAR_TO_INT(m_strInt.at(i));
			fstNum = CHAR_TO_INT(b.GetStrInt().at(j));
		}
		
		diff = fstNum - sndNum - carry;		
		// 处理借位
		if (diff < 0)
		{			
			if (i != 0 || j != 0)
			{
				diff = 10 + diff;
			}
			carry = 1;
		}
		else
		{			
			carry = 0;
		}
		if (i == 0 && j == 0) // 最后一位
		{
			if (diff > 0)
			{
				strResult.append(string(1, INT_TO_CHAR(diff))); // 先顺序加				
			}
		}
		else
		{
			strResult.append(string(1, INT_TO_CHAR(diff))); // 先顺序加				
		}
		i--;
		j--;
	}
	
	// 处理剩余部分
	if (nCmp > 0)
	{
		if (i >= 0)
		{
			// 处理可能借位的最高位
			diff = CHAR_TO_INT(m_strInt.at(i)) - carry;
			if (diff > 0) // 防止将0插入
			{
				strResult.append(string(1, INT_TO_CHAR(diff))); // 先顺序加
			}			
			i--;
			while (i >= 0)
			{			
				strResult.append(string(1, m_strInt.at(i)));
				i--;
			}
		}	
	}	
	else
	{
		if (j >= 0)
		{
			// 处理可能借位的最高位
			diff = CHAR_TO_INT(b.GetStrInt().at(j)) - carry;
			if (diff > 0) // 防止将0插入
			{
				strResult.append(string(1, INT_TO_CHAR(diff))); // 先顺序加
			}
			j--;
			while (j >= 0)
			{
				strResult.append(string(1, b.GetStrInt().at(j)));
				j--;
			}
		}		
	}
	
	// 反转结果
	reverse(strResult.begin(), strResult.end());
	return (nCmp > 0) ? BigInt(strResult).DelZeroNeg() : (-BigInt(strResult)).DelZeroNeg();
}

// 正数乘法(纯正数乘法,不考虑负号)
BigInt BigInt::Mul(BigInt& b)
{
	// 直接对0做处理
	if (*this == BigInt("0") || b == BigInt("0"))
	{
		return BigInt("0");
	}
	string strResult; // 保存结果的字符串
	int nLen = m_strInt.length() - 1, nbLen = b.GetStrInt().length() - 1;
	int carry = 0; // 保存乘法的进位
	int mul; // 保存乘法的结果
	int i, j;
	BigInt biResult;
	for (i = nbLen; i >= 0; i--)
	{
		strResult = ""; // 保存个位乘以b的值
		carry = 0;
		for (j = nLen; j >= 0; j--)
		{
			mul = CHAR_TO_INT(m_strInt.at(j)) * CHAR_TO_INT(b.GetStrInt().at(i)) + carry;
			if (mul < 10)
			{
				strResult.append(string(1, INT_TO_CHAR(mul)));
				carry = 0;
			}
			else
			{
				while (mul >= 10)
				{
					strResult.append(string(1, INT_TO_CHAR(mul % 10)));
					carry = mul /= 10;
				}
			}
		}
		// 最后所剩的高位
		if (carry != 0)
		{
			strResult.append(string(1, INT_TO_CHAR(carry)));
		}		
		// 翻转成正常数位
		reverse(strResult.begin(), strResult.end());
		// 移位乘以10,即末尾补0
		strResult.append(string(nbLen - i, '0'));
		biResult = biResult.Add(BigInt(strResult)); // 将结果相加
	}
	
	return biResult.DelZeroNeg();
}

// 正数除法(纯正数除法,不考虑负号)
BigInt BigInt::Div(BigInt& b)
{
	// 检查除数是否为0
	if (b == BigInt("0"))
	{
		throw bigint_error("除数为0");
	}
	int nCmp = Cmp(b);
	if (nCmp == 0) // 若相等
	{
		return BigInt("1");
	}
	else
	{
		int cnt = 0;
		BigInt biTmp(*this);
		while (biTmp >= b)
		{
			cnt++;
			biTmp = biTmp - b;
		}
		char cTmp[100];
		itoa(cnt, cTmp, 10);
		return BigInt(cTmp).DelZeroNeg();
	}
}

// 正数取余(纯正数取余,不考虑负号)
BigInt BigInt::Mod(BigInt& b)
{
	return (*this - Div(b) * b).DelZeroNeg();
}

// 正数比较,返回值> 0 则>,< 0 则小, == 0则相等
int BigInt::Cmp(BigInt& b)
{
	int nLen = m_strInt.length();
	int nbLen = b.GetStrInt().length();
	if (nLen > nbLen)
	{
		return 1;
	}
	else if (nLen < nbLen)
	{
		return -1;
	}
	else
	{
		int i;
		for (i = 0; i < nLen; ++i) // 逐位比较,从高位开始比较
		{
			if (m_strInt.at(i) > b.GetStrInt().at(i))
			{
				return 1;
			}
			else if (m_strInt.at(i) < b.GetStrInt().at(i))
			{
				return -1;
			}
		}
	}
	return 0; // 相等
}

// 是否为0,消除0与-0的差别
bool BigInt::IsZero()
{
	if (m_strInt.length() > 2)
	{
		return false;
	}
	if (m_strInt.at(0) == '0' && m_strInt.length() == 1)
	{
		return true;
	}
	else if (m_strInt.at(0) == '-' && m_strInt.at(1) == '0' && m_strInt.length() == 2)
	{
		return true;
	}
	else
	{
		return false;
	}
}

// 若为0,消除负号,否则返回原样
BigInt& BigInt::DelZeroNeg()
{
	if (IsZero())
	{
		m_strInt = "0";
	}
	return *this;
}

// 取负
BigInt BigInt::operator - ()
{
	if (!IsLegal())
	{
		throw bigint_error("一元operator - 操作数含有非法字符");
	}
	BigInt b(*this);
	bool bNeg = false;
	if (b.m_strInt.at(0) == MINUS_SYMBOL)
	{
		bNeg = true;
	}
	// 若已经为负数
	if (bNeg)
	{
		b.m_strInt.erase(0, 1); // 删除负号(删除第一个字符)
	}
	else // 若为正数
	{
		b.m_strInt.insert(0, string(1, MINUS_SYMBOL)); // 插入负号
	}
	return b.DelZeroNeg();
}

// 赋值
BigInt& BigInt::operator = (BigInt& b)
{
	if (!b.IsLegal())
	{
		throw bigint_error("operator = 操作数含有非法字符");
	}
	m_strInt.assign(b.GetStrInt().begin(), b.GetStrInt().end());
	return *this;
}

// 赋值
BigInt& BigInt::operator = (const string& b)
{
	if (!BigInt(b).IsLegal())
	{
		throw bigint_error("operator = 操作数含有非法字符");
	}
	m_strInt.assign(b.begin(), b.end());
	return *this;
}

// 自增
BigInt& BigInt::operator ++ ()
{
	*this = *this + BigInt("1");
	return *this;
}
// 自增,后置
BigInt BigInt::operator ++ (int)
{
	BigInt b = *this;
	*this = *this + BigInt("1");
	return b;
}
// 自减
BigInt& BigInt::operator -- ()
{
	*this = *this - BigInt("1");
	return *this;
}
// 自减,后置
BigInt BigInt::operator -- (int)
{
	BigInt b = *this;
	*this = *this - BigInt("1");
	return b;
}

// 赋值 +=
BigInt& BigInt::operator += (BigInt& b)
{
	*this = *this + b;
	return *this;
}
// 赋值 -=
BigInt& BigInt::operator -= (BigInt& b)
{
	*this = *this - b;
	return *this;
}
// 赋值 *=
BigInt& BigInt::operator *= (BigInt& b)
{
	*this = *this * b;
	return *this;
}
// 赋值 /=
BigInt& BigInt::operator /= (BigInt& b)
{
	*this = *this / b;
	return *this;
}
// 赋值 %=
BigInt& BigInt::operator %= (BigInt& b)
{
	*this = *this % b;
	return *this;
}

// 比较运算 >
bool operator > (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator > 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator > 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	if (bB1Neg && !bB2Neg) // 如果b1负但b2正
	{
		return false; // b1 < b2
	}
	else if (!bB1Neg && bB2Neg) // 如果b1正但b2负
	{
		return true; // b1 > b2
	}
	else if (bB1Neg && bB2Neg) // b1与b2均负
	{		
		return (-b1).Cmp(-b2) < 0; // 若absB1 < absB2,则b1 > b2
	}
	else // b1与b2均为正
	{
		return b1.Cmp(b2) > 0; // b1 > b2
	}
}

// 比较运算 >=
bool operator >= (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator >= 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator >= 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	if (bB1Neg && !bB2Neg) // 如果b1负但b2正
	{
		return false; // b1 < b2
	}
	else if (!bB1Neg && bB2Neg) // 如果b1正但b2负
	{
		return true; // b1 > b2
	}
	else if (bB1Neg && bB2Neg) // b1与b2均负
	{		
		return (-b1).Cmp(-b2) <= 0; // 若absB1 <= absB2,则b1 >= b2
	}
	else // b1与b2均为正
	{
		return b1.Cmp(b2) >= 0; // b1 >= b2
	}
}

// 比较运算 <
bool operator < (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator < 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator < 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	if (bB1Neg && !bB2Neg) // 如果b1负但b2正
	{
		return true; // b1 < b2
	}
	else if (!bB1Neg && bB2Neg) // 如果b1正但b2负
	{
		return false; // b1 > b2
	}
	else if (bB1Neg && bB2Neg) // b1与b2均负
	{		
		return (-b1).Cmp(-b2) > 0; // 若absB1 > absB2,则b1 < b2
	}
	else // b1与b2均为正
	{
		return b1.Cmp(b2) < 0; // b1 < b2
	}
}
// 比较运算 <=
bool operator <= (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator <= 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator <= 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	if (bB1Neg && !bB2Neg) // 如果b1负但b2正
	{
		return true; // b1 < b2
	}
	else if (!bB1Neg && bB2Neg) // 如果b1正但b2负
	{
		return false; // b1 > b2
	}
	else if (bB1Neg && bB2Neg) // b1与b2均负
	{		
		return (-b1).Cmp(-b2) >= 0; // 若absB1 >= absB2,则b1 <= b2
	}
	else // b1与b2均为正
	{
		return b1.Cmp(b2) <= 0; // b1 <= b2
	}
}
// 比较运算 ==
bool operator == (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator == 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator == 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	if ((bB1Neg && !bB2Neg) || (!bB1Neg && bB2Neg)) // 如果b1负但b2正
	{
		return false; // b1 != b2
	}
	else if (bB1Neg && bB2Neg) // b1与b2均负
	{		
		return (-b1).Cmp(-b2) == 0; // 若absB1 == absB2,则b1 == b2
	}
	else // b1与b2均为正
	{
		return b1.Cmp(b2) == 0; // b1 == b2
	}
}
// 比较运算 !=
bool operator != (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator != 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator != 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	if ((bB1Neg && !bB2Neg) || (!bB1Neg && bB2Neg)) // 如果b1负但b2正
	{
		return true; // b1 != b2
	}
	else if (bB1Neg && bB2Neg) // b1与b2均负
	{		
		return (-b1).Cmp(-b2) != 0; // 若absB1 == absB2,则b1 == b2
	}
	else // b1与b2均为正
	{
		return b1.Cmp(b2) != 0; // b1 == b2
	}
}

// 输出
ostream& operator << (ostream& os, BigInt& b)
{
	if (!b.IsLegal())
	{
		throw bigint_error("operator << 操作数含有非法字符");
	}
	return os << b.GetStrInt();
}

// 友元函数,大整数类加法
BigInt operator + (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator + 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator + 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	// 如果都是负数
	if (bB1Neg && bB2Neg)
	{
		return (-((-b1).Add(-b2))).DelZeroNeg();
	}
	else if (!bB1Neg && !bB2Neg) // 都为正数
	{
		return (b1.Add(b2)).DelZeroNeg();
	}
	else if (bB1Neg && !bB2Neg) // b1为负,b2为正
	{
		return (b2.Sub(-b1)).DelZeroNeg();
	}
	else // b1为正,b2为负
	{
		return (b1.Sub(-b2)).DelZeroNeg();
	}
}

// 友元函数,大整数类乘法
BigInt operator - (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator - 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator - 第二个操作数含有非法字符");
	}
 	return (b1 + (-b2)).DelZeroNeg();
}

// 友元函数,大整数类乘法
BigInt operator * (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator * 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator * 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	// 如果都是负数或都为正数
	if (!bB1Neg && !bB2Neg)
	{
		return (b1.Mul(b2)).DelZeroNeg();
	}
	else if (bB1Neg && bB2Neg)
	{
		return ((-b1).Mul(-b2)).DelZeroNeg();
	}
	else if (!bB1Neg && bB2Neg)	
	{
		return (-b1.Mul(-b2)).DelZeroNeg();
	}
	else
	{
		return (-b2.Mul(-b1)).DelZeroNeg();
	}
}

// 友元函数,大整数类除法
BigInt operator / (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator / 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator / 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	// 如果都是负数或都为正数
	if (!bB1Neg && !bB2Neg)
	{
		return (b1.Div(b2)).DelZeroNeg();
	}
	else if (bB1Neg && bB2Neg)
	{
		return ((-b1).Div(-b2)).DelZeroNeg();
	}
	else if (!bB1Neg && bB2Neg)	
	{
		return (-b1.Div(-b2)).DelZeroNeg();
	}
	else
	{
		return (-(-b1).Div(b2)).DelZeroNeg();
	}
}

// 友元函数,大整数类取余
BigInt operator % (BigInt& b1, BigInt& b2)
{
	// 判断b1, b2是否合法
	if (!b1.IsLegal())
	{
		throw bigint_error("operator % 第一个操作数含有非法字符");
	}
	if (!b2.IsLegal())
	{
		throw bigint_error("operator % 第二个操作数含有非法字符");
	}
	bool bB1Neg = false, bB2Neg = false; // 判断b1, b2的符号位(是否为负数)
	if (b1.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB1Neg = true;
	}
	if (b2.GetStrInt().at(0) == MINUS_SYMBOL) // 第一个操作数是否为负号
	{
		bB2Neg = true;
	}
	// 如果都是负数或都为正数
	if (!bB1Neg && !bB2Neg)
	{
		return (b1.Mod(b2)).DelZeroNeg();
	}
	else if (bB1Neg && bB2Neg)
	{
		return (-(-b1).Mod(-b2)).DelZeroNeg();
	}
	else if (!bB1Neg && bB2Neg)	
	{
		return (b1.Mod(-b2)).DelZeroNeg();
	}
	else
	{
		return (-(-b1).Mod(b2)).DelZeroNeg();
	}
}

但是其中有一个疑问如下:

倘若一个函数的签名为(const BigInt& b),即常引用,在函数体内调用b.IsLegal()则会报错:vc1.cpp(29487) : error C2662: 'IsLegal' : cannot convert 'this' pointer from 'const class BigInt' to 'class BigInt &' Conversion loses qualifiers,可是我观察IsLegal函数的代码,发现似乎并没有去改动BigInt&本身的属性,这就造成我的困惑于不解,再将IsLegal的代码贴出如下:

// 判断大整数是否合法
bool BigInt::IsLegal()
{
	bool bRet;
	// 对于个位数
	if (m_strInt.length() == 1)
	{
		// 判断是否含有除负号之外的所有字符
		// 若找到其他字符,则返回false
		return !(m_strInt.find_first_not_of(m_cstrLegalChar.substr(0, m_cstrLegalChar.length() - 1)) != string::npos);
	}
	else // 对于多位数
	{
		bRet = true;
		// 判断第一位,可含符号位
		bRet &= (m_cstrLegalChar.find(m_strInt.at(0)) != string::npos);
		// 判断余下位数
		bRet &= !(m_strInt.substr(1).find_first_not_of(m_cstrLegalChar.substr(0, m_cstrLegalChar.length() - 1)) != string::npos);
		return bRet;
	}
}

 希望走过路过的朋友们给予指出,谢谢。

最后给出测试代码,如求200的阶乘,代码如下:

int main()
{
	try
	{
		// 示例,求阶乘
		BigInt fact = "1";
		BigInt index, num = "200";
		for (index = "2"; index <= num; ++index)
		{
			fact *= index;
		}
		cout << num << "! = " << fact << endl;
	}
	catch (bigint_error& e)
	{
		cerr << e.what() << endl;
	}
	return 0;
}

结果输出为:

200! = 7886578673647905035523632139321850622951359776871732632947425332443594499
63403342920304284011984623904177212138919638830257642790242637105061926624952829
93111346285727076331723739698894392244562145166424025403329186413122742829485327
75242424075739032403212574055795686602260319041703240623517008587961789222227896
23703897374720000000000000000000000000000000000000000000000000

使用matlab对比,发现结果完全正确。(当然期间我已经做了大量的测试用例才能达到这种结果)

在平安夜,一个剩蛋,没有mm相伴,写下这些代码,希望能和园子里的朋友互相学习,这也是我第一篇随笔。*^_^*

posted on 2010-12-25 12:16  万户侯  阅读(696)  评论(1编辑  收藏  举报

导航