大整数类的实现包含了加减乘除运算

  • Post author:
  • Post category:其他


大整数在笔面试中也是常考的,所以抽时间自己实现了一个大整数类,思想是通过一个vector<int> 来存储数据,每一个元素代表万进制大整数中的一位。具体程序如下:

#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <vector>
using namespace std;

class BigInt
{
public:
	//利用字符串来构造一个大整数
	BigInt(string s)
	{
		int left=0;
		symbol=1; //默认为正数  
		if (s.size()>0)
		{
			if (s[0]=='-')
			{
				symbol=-1;
				left=1;
			}
			else if (s[0]=='+')
			{
				
				left=1;
			}
		}
		for (int i=s.size();i>left;i-=REDIX_LEN)
		{
			int low=max(i-REDIX_LEN,left);
			int result=0;
			for (int j=low;j<i;++j)
			{
				result=result*10+s[j]-'0';
			}
			elem.push_back(result);
		}
	}
	//将大整数转化为字符串,用于输出
	string toString()
	{
		stringstream result;
		bool flag=false; //标记是否在操作最高位
		for (int i=elem.size()-1;i>=0;--i)
		{	
			if (flag)  //跳过了最高位,每一位都需要以四位长度等宽输出,不足左边补0
			{
				result<<setfill('0')<<setw(4)<<elem[i];

			}
			else
			{
				//最高位需要特殊处理,因为可能需要输出负号,且不足4位不用补0
				if (symbol==-1)
				{
					result<<'-';
				}
				result<<elem[i];
				flag=true;
			}
				
		}
		if (!flag)  //如果elem为空,输出0
		{
			return "0";
		}
		return result.str();
	}
	//相当于两个数的绝对值相加,不考虑符号
	static BigInt add(const BigInt &x,const BigInt &y)
	{
		int maxLen=max(x.elem.size(),y.elem.size())+1;  //两个数和不会超过最大数的位数+1
		vector<int> z(maxLen,0);
		int i=0;
		for (;i<x.elem.size() && i<y.elem.size();++i)
		{
			z[i]+=x.elem[i]+y.elem[i];
			int carry=z[i]/BIGINT_REDIX;
			z[i]%=BIGINT_REDIX;
			z[i+1]+=carry;
		}
		while(i<x.elem.size())
		{
			z[i]+=x.elem[i];
			int carry=z[i]/BIGINT_REDIX;
			z[i]%=BIGINT_REDIX;
			z[i+1]+=carry;
			++i;
		}
		while(i<y.elem.size())
		{
			z[i]+=y.elem[i];
			int carry=z[i]/BIGINT_REDIX;
			z[i]%=BIGINT_REDIX;
			z[i+1]+=carry;
			++i;
		}
		//去掉高位中的0
		while(!z.empty() && z.back()==0)
		{
			z.pop_back();
		}
		return BigInt(z,1);
	}
	BigInt operator+(const BigInt &rhs)
	{
		if (this->symbol==1 && rhs.symbol==1)  //两个正数相加
		{
			return add(*this,rhs);
		}
		else if (this->symbol==-1 && rhs.symbol==-1)  //两个负数相加
		{
			BigInt tmp=add(*this,rhs);
			tmp.symbol=-1;
			return tmp;
		}
		else if (this->symbol==1)    //正数加上负数
		{
			if (*this>=rhs)
			{
				return sub(*this,rhs);
			}
			else
			{
				BigInt tmp=sub(rhs,*this);
				tmp.symbol=-1;
				return tmp;
			}
		}
		else            //负数加上正数
		{
			if (*this>=rhs)
			{
				BigInt tmp=sub(*this,rhs);
				tmp.symbol=-1;
				return tmp;
			}
			else
			{
				return sub(rhs,*this);
			}
		}
	}

	//x必须大于y,且两者都非负
	static BigInt sub(const BigInt &x,const BigInt &y)
	{
		vector<int> z(x.elem.size()+1,0);  //因为x>y所以,x-y位数不会超过x的位数+1
		int i=0;
		for (;i<y.elem.size();++i)
		{
			z[i]+=x.elem[i]-y.elem[i];
			if (z[i]<0)
			{
				z[i]+=BIGINT_REDIX;
				z[i+1]-=1;
			}
		}
		while(i<x.elem.size())
		{
			z[i]+=x.elem[i];
			if (z[i]<0)
			{
				z[i]+=BIGINT_REDIX;
				z[i+1]-=1;
			}
			++i;
		}
		while(!z.empty() && z.back()==0)
		{
			z.pop_back();
		}
		return BigInt(z,1);
	}
	BigInt operator-(const BigInt &rhs)
	{
		if (this->symbol==1 && rhs.symbol==1)  //正数减正数
		{
			if (*this>=rhs)
			{
				return sub(*this,rhs);
			}
			else
			{
				BigInt tmp=sub(rhs,*this);
				tmp.symbol=-1;
				return tmp;
			}

		}
		else if (this->symbol==-1 && rhs.symbol==-1)  //负数减负数
		{
			if (*this>=rhs)
			{
				BigInt tmp=sub(*this,rhs);
				tmp.symbol=-1;
				return tmp;
			}
			else
			{
				return sub(rhs,*this);
			}
		}
		else if (this->symbol==1)   //正数减负数
		{
			return add(*this,rhs);
		}
		else                        //负数减正数
		{
			BigInt tmp=add(*this,rhs);
			tmp.symbol=-1;
			return tmp;
		}
	}
	//判断个大整数的绝对值大小
	bool operator>=(const BigInt &rhs)
	{
		if (this->elem.size()>rhs.elem.size())
		{
			return true;
		}
		else if (this->elem.size()<rhs.elem.size())
		{
			return false;
		}
		else
		{
			for (int i=this->elem.size()-1;i>=0;--i)
			{
				if (this->elem[i]<rhs.elem[i])
				{
					return false;
				}
			}
			return true;
		}
	}
	//大整数乘积,考虑了符号
	static BigInt multiply(const BigInt &x,const BigInt &y)
	{
		vector<int> z(x.elem.size()+y.elem.size(),0);
		for (int i=0;i<x.elem.size();++i)
		{
			for (int j=0;j<y.elem.size();++j)
			{
				z[i+j]+=x.elem[i]*y.elem[j];
				int carry=z[i+j]/BIGINT_REDIX;
				z[i+j]%=BIGINT_REDIX;
				z[i+j+1]+=carry;
			}
		}
		while(!z.empty() && z.back()==0)
		{
			z.pop_back();
		}
		//判断乘积的符号
		int flag=1;
		if (x.symbol*y.symbol<0)
		{
			flag=-1;
		}
		return BigInt(z,flag);
	}
	BigInt operator*(const BigInt &rhs)
	{
		return multiply(*this,rhs);
	}

	static BigInt div(const BigInt &x,const BigInt &y)
	{
		vector<int> z(x.elem.size()+1,0);
		vector<int> tmpY(x.elem.size(),0);
		BigInt tmpX(x);
		const int times=x.elem.size()-y.elem.size();
		//tmpY看成y中elem的副本左移到和x中elem位数一样多的结果
		for (int i=x.elem.size()-1;i>=0 ;--i)
		{
			if (i>=times)
			{
				tmpY[i]=y.elem[i-times];
			}
			else
			{
				tmpY[i]=0;
			}
		}
		/* 先减去若干个 y×(10000 的 times 次方),
		不够减了,再减去若干个 y×(10000 的 times-1 次方)
		一直减到不够减为止 */
		for (int i=0;i<=times;++i)
		{
			const BigInt tmpInt(tmpY,1);
			while(tmpX>=tmpInt)
			{
				++z[times-i];
				tmpX=sub(tmpX,tmpInt);
			}
			for (int j=0;j<tmpY.size()-1;++j)
			{
				tmpY[j]=tmpY[j+1];
			}
			tmpY.pop_back();
		}
		//统一处理进位
		for (int i=0;i<z.size()-1;++i)
		{
			int carry=z[i]/BIGINT_REDIX;
			z[i]%=BIGINT_REDIX;
			z[i+1]+=carry;
		}
		//去掉高位的0
		while(!z.empty() && z.back()==0)
		{
			z.pop_back();
		}
		//判断商的符号
		int flag=1;
		if (x.symbol*y.symbol<0)
		{
			flag=-1;
		}
		return BigInt(z,flag);
	}
	BigInt operator/(const BigInt &rhs)
	{
		return div(*this,rhs);
	}
private:
	//用于运算中返回结果时,根据elem构造大整数
	BigInt(vector<int> vec,int flag):elem(vec),symbol(flag){};
	vector<int> elem;  //大整数的数据,每一个元素代表万进制中的一位
	int symbol; //1为正,-1为负
	//万进制的数,vector中的每一个元素当做大整数的万进制的一位
	static const int REDIX_LEN=4;
	static const int BIGINT_REDIX=10000;

};

int _tmain(int argc, _TCHAR* argv[])
{
	string x;
	string y;
	while(cin>>x>>y)
	{
		BigInt first(x),second(y);
		cout<<"两个数的和为: "<<(first+second).toString()<<endl;
		cout<<"两个数的差为: "<<(first-second).toString()<<endl;
		cout<<"两个数的积为: "<<(first*second).toString()<<endl;
		cout<<"两个数的商为: "<<(first/second).toString()<<endl;
	}
	return 0;
}

程序运行结果如下:



版权声明:本文为shineboyxxb原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。