大数计算(进阶) 支持大浮点数的任意精度加减乘除

上一篇实现了大数加法,乘除法都是简单的复用加法,这样做时间复杂度高,精度低。

进阶:

1.乘法模拟竖式计算方法 核心思路是num1[i]*num2[j]的结果一定对应乘积中的[i+j]位,并且考虑对[i+j+1]位的进位。

    这样的时间复杂度为O(m*n) 而简单的复用加法的时间复杂度为 (q/p)*(n+m)其中q,p为大数的实际值,n,m为大数的位数,这样当p很小的时候,时间复杂度会很大。进一步优化的方法是使用FFT即快速傅里叶变换。下一篇中进行升级。

	Num by(Num& a,Num&b)
	{
		Num ret;
		int pos1=a._float.length();
		int pos2=b._float.length();

		string s1,s2,s(1000,'0');
		s1=a._int+a._float;
		s2=b._int+b._float;

		reverse(s1.begin(),s1.end());  
        reverse(s2.begin(),s2.end());  
        for(int i=0;i<s1.length();i++)  
			for(int j=0;j<s2.length();j++)  
			{  
				int temp=(s1[i]-'0')*(s2[j]-'0');  
				s[i+j+1]=s[i+j+1]-'0'+(s[i+j]-'0'+temp)/10+'0';  
				s[i+j]=(s[i+j]-'0'+temp)%10+'0';  
			}
		reverse(s.begin(),s.end());  
		ret._int=s;
		int pos=s.length()-pos1-pos2+1;
		ret._int.resize(pos);
		ret._int[pos-1]='\0';

		int len=pos1+pos2;
		string::reverse_iterator rts=s.rbegin();
		while(rts!=s.rend()&&len>0)
		{
			ret._float.insert(0,1,*rts);
			rts++;
			len--;
		}

		if(a._sign==b._sign)
			ret._sign=POSITIVE;
		else 
			ret._sign=NEGATIVE;


		ret._int=ret.InputNum(ret._int).second._int;
		return ret;
	}


2.除法模拟竖式计算。为满足浮点计算,引入新的标志:精度。每一个大数对象都拥有一个进度,在运算除法时,返回的结果精度由被除数的精度,除数的小数位数共同决定。

核心算法为大数除以整数。处理两个浮点大数相除的时候,将两个大数的小数位对齐到整数位,记录对齐位数。将被除数的整数位额外对齐 10e精度 倍。计算结束后,取结果的0~精度-1为整数位,精度~end为小数位 处理符号位后返回计算结果。

	Num except(Num& a,Num& b)
	{
		int len1=a._float.length();
		int len2=b._float.length();
		int _precision=a._pos;
		string aa=a._int+a._float;
		string bb=b._int+b._float;
		string tmp;
		string ans;
		Num cop1,cop2,ret;
		int ok=0;
		for(int i=0;i<len1;i++)
		{
		bb+='0';
		}
		for(int i=0;i<len2+_precision;i++)
		{
		aa+='0';
		}
		cop2._int=bb;
		for(int i=0;i<aa.size();i++)
		{
			tmp+=aa[i];
			cop1._int=tmp;
			if(cop1>=cop2)
			{
			ok=1;
			int ex=(_exc(tmp,bb));
			ans+=(ex+'0');
			//char arr[3]={0};
			//itoa(ex,arr,10);
			Num ttmp;
			ttmp._int+=ex+'0';
			tmp=reduce(cop1,by(cop2,ttmp))._int;
			}
			else/* if(ok==1)*/
			{
				ans+='0';
			}
		}
		/*****************************核心算法****事实上要处理除数是字符串,以及提高运算精度等问题**********
                           // for(int i=0;i<s.size();i++)  
                           // {  
                           // cmp=(cmp*10+s[i]-'0');  
                           // if(cmp>=x)  
                           // {  
                           // ok=1;  
                           // ans+=(cmp/x+'0');  
                           // cmp%=x;  
                           // }  
                           // else{  
                           // ans+='0'; 
                           // }  
                           // }  
		******************************************************************************************/
		string::iterator it=ans.begin();
		int intlen=ans.length()-_precision;
		while(it!=ans.end()&&intlen>0)
		{
			ret._int+=*it;
			it++;
			intlen--;
		}
		string::reverse_iterator rt1=ans.rbegin();
		while(_precision>0&&rt1!=ans.rend())
		{
			ret._float.insert(0,1,*rt1);
			rt1++;
			_precision--;
		}
		while(_precision>0)
		{
			ret._float.insert(0,1,'0');
			_precision--;
		}
		ret._int=InputNum(ret._int).second._int;
		return ret;
	}

	int _exc(string& a,string& b)
	{
		int len1=a.length();
		int len2=b.length();
		int ret=0;
		Num bb;
		Num tmp1,tmp2;
		bb._int=b;
		tmp1._int=a;
		tmp2._int=b;
		if(tmp1<tmp2)
			return 0;
		while(tmp1>=tmp2)
		{
			ret++;
			tmp2=tmp2.add(tmp2,bb);
		}
		return ret;
	}

完整代码

#pragma once
#include <string>
#include <cstring>
#include <string.h>
#define POS 10	//精度
using namespace std;

enum SIGN
{
	POSITIVE,
	NEGATIVE
};

typedef class Num
{
protected:
	SIGN _sign;
	string _int;
	string _float;

	int _pos;//精度
public:
	Num()
		:_sign(POSITIVE),
		_pos(POS)
	{}

	Num(Num& a)
	{
		_sign=a._sign;
		_int=a._int;
		_float=a._float;
		_pos=a._pos;
	}

	int precision(int x)
	{
	_pos=x;
	return _pos;
	}

	bool IsZero(Num& a)
	{
		string::iterator it1=a._int.begin();
		string::iterator it2=a._float.begin();
		while(it1!=a._int.end())
		{
		if(*it1!='0')
			return false;
		it1++;
		}
		while(it2!=a._float.end())
		{
		if(*it2!='0')
			return false;
		it2++;
		}
		return true;
	}

	bool IsZero()
	{
		string::iterator it1=_int.begin();
		string::iterator it2=_float.begin();
		while(it1!=_int.end())
		{
		if(*it1!='0')
			return false;
		it1++;
		}
		while(it2!=_float.end())
		{
		if(*it2!='0')
			return false;
		it2++;
		}
		return true;
	}

	bool operator>(Num& a)
	{
		if(IsZero(*this)&&IsZero(a))
			return false;
		if(_sign==NEGATIVE&&a._sign==POSITIVE)
			return false;
		else if(_sign==POSITIVE&&a._sign==NEGATIVE)
			return true;

		if(_sign==POSITIVE&&a._sign==POSITIVE)
		{
			if(_int.length()>a._int.length())
				return true;
			else if(_int.length()<a._int.length())
				return false;
			else if(_int.length()==a._int.length())
			{
				if(strcmp(_int.c_str(),a._int.c_str())<0)
					return false;
				else if(strcmp(_int.c_str(),a._int.c_str())>0)
					return true;
				else if(strcmp(_int.c_str(),a._int.c_str())==0)
				{
				string::iterator it1=_float.begin();
				string::iterator it2=a._float.begin();

				while(it1!=_float.end()&&it2!=a._float.end())
				{
					if(*it1<*it2)
						return false;
					it1++;
					it2++;
				}
				while(it2!=a._float.end())
				{
					return false;
				}
				while(it1!=_float.end())
				{
					return true;
				}
				}
				return false;
			}
		}

		if(_sign==NEGATIVE&&a._sign==NEGATIVE)
		{
			if(_int.length()>a._int.length())
				return false;
			else if(_int.length()<a._int.length())
				return true;
			else if(_int.length()==a._int.length())
			{
				if(strcmp(_int.c_str(),a._int.c_str())<0)
					return true;
				else if(strcmp(_int.c_str(),a._int.c_str())>0)
					return false;
				else if(strcmp(_int.c_str(),a._int.c_str())==0)
				{
				string::iterator it1=_float.begin();
				string::iterator it2=a._float.begin();

				while(it1!=_float.end()&&it2!=a._float.end())
				{
					if(*it1<*it2)
						return true;
					else if(*it1>*it2)
						return false;
					it1++;
					it2++;
				}
				while(it1!=_float.end())
				{
					return false;
				}
				while(it2!=a._float.end())
					return true;
				}
				return false;
			}
		}
		return true;
	}

	bool operator==(Num& a)
	{
		if(IsZero(*this)&&IsZero(a))
			return true;
		if(_sign==NEGATIVE&&a._sign==POSITIVE)
			return false;
		else if(_sign==POSITIVE&&a._sign==NEGATIVE)
			return false;

		if(_int.length()!=a._int.length()||_float.length()!=a._float.length())
			return false;
		else if(_int.length()==a._int.length()&&strcmp((_int.c_str()),a._int.c_str())!=0)
			return false;
		else if(_float.length()==a._float.length()&&strcmp((_float.c_str()),a._float.c_str())!=0)
			return false;

		return true;
	}

	bool operator<(Num& a)
	{
	return !(*this>a||*this==a);
	}

	bool operator>=(Num& a)
	{
	return *this>a||*this==a;
	}

	bool operator<=(Num& a)
	{
	return *this<a||*this==a;
	}

	Num& operator=(Num a)
	{
		_float=a._float;
		_int=a._int;
		_sign=a._sign;
		return *this;
	}

	Num _abs()
	{
		Num ret(*this);
		ret._sign=POSITIVE;
		return ret;
	}

	Num& operator++()
	{
		Num one;
		one._int='1';
		return *this=add(*this,one);
	}

	Num operator++(int)
	{
		Num ret=*this;
		Num one;
		one._int='1';
		*this=add(*this,one);
		return ret;
	}

	Num& operator--()
	{
		Num one;
		one._int='1';
		one._sign=NEGATIVE;
		return *this=add(*this,one);
	}

	Num operator--(int)
	{
		Num ret=*this;
		Num one;
		one._sign=NEGATIVE;
		one._int='1';
		*this=add(*this,one);
		return ret;
	}

	Num operator+(Num& a)
	{
		return add(*this,a);
	}

	Num operator-(Num& a)
	{
		return  reduce(*this,a);
	}

	Num operator*(Num& a)
	{
		return by(*this,a); 
	}

	Num operator/(Num& a)
	{
		if(IsZero(a))
		{
		perror("/ 0 ");
		exit(1);
		}
		return except(*this,a); 
	}

	Num add(Num& a,Num& b)
	{
		Num ret;
		int flag=0;//进位符
		if(a.IsZero())
			return b;
		if(b.IsZero())
			return a;
		if(a._sign==b._sign)//同号相加
		{
			ret._sign=a._sign;
			int len1=a._float.length();
			int len2=b._float.length();
			string::reverse_iterator rt1=a._float.rbegin();
			string::reverse_iterator rt2=b._float.rbegin();
			while(len1>len2)//小数部分
			{
				len1--;
				ret._float.insert(0,1,*rt1);
				rt1++;
			}
			while(len2>len1)
			{
				len2--;
				ret._float.insert(0,1,*rt2);
				rt2++;
			}
			while(len1==len2&&rt1!=a._float.rend()&&rt2!=b._float.rend())
			{
				int tmp=(*rt1-'0')+(*rt2-'0')+flag;
				flag=tmp/10;
				tmp=tmp%10;
				ret._float.insert(0,1,tmp+'0');
				rt2++;
				rt1++;
				len1--;
				len2--;
			}

			rt1=a._int.rbegin();
			rt2=b._int.rbegin();

			while(rt1!=a._int.rend()&&rt2!=b._int.rend())
			{
				int tmp=(*rt1-'0')+(*rt2-'0')+flag;
				flag=tmp/10;
				tmp=tmp%10;
				ret._int.insert(0,1,tmp+'0');
				rt2++;
				rt1++;
			}
			while(rt1!=a._int.rend())
			{
				int tmp=(*rt1-'0')+flag;
				flag=tmp/10;
				tmp=tmp%10;
				ret._int.insert(0,1,tmp+'0');
				rt1++;
			}
			while(rt2!=b._int.rend())
			{
				int tmp=(*rt2-'0')+flag;
				flag=tmp/10;
				tmp=tmp%10;
				ret._int.insert(0,1,tmp+'0');
				rt2++;
			}
			if(flag)
				ret._int.insert(0,1,'1');
		}

		if(a._sign!=b._sign)		//异号相加
		{
			Num aa=a,bb=b;
			if(a._abs()<b._abs())
			{
				swap(aa,bb);
			}
			else if(a._abs()==b._abs())
				return ret;

			//先计算小数位
			string::reverse_iterator rt1=aa._float.rbegin();//a>b
			string::reverse_iterator rt2=bb._float.rbegin();
			int len1=aa._float.length();
			int len2=bb._float.length();
			while(len1>len2)
			{
				ret._float.insert(0,1,*rt1);
				len1--;
				rt1++;
			}
			while(len1<len2)
			{
				int tmp=10-(flag+*rt2-'0');
				flag=1;
				rt1++;
				len2--;
			}
			while(len1==len2&&rt1!=aa._float.rend()&&rt2!=bb._float.rend())
			{
				int tmp=(*rt1-'0')-(flag+*rt2-'0');
				if(tmp<0)
				{
					flag=1;
					tmp+=10;
				}
				else if(tmp>0)
				{
					flag=0;
				}
				ret._float.insert(0,1,tmp+'0');
				rt1++;
				rt2++;
				len1--;
				len2--;
			}

			rt1=aa._int.rbegin();//计算整数部分
			rt2=bb._int.rbegin();
			while(rt1!=aa._int.rend()&&rt2!=bb._int.rend())
			{
				int tmp=(*rt1-'0')-(flag+*rt2-'0');
				if(tmp<0)
				{
					flag=1;
					tmp+=10;
				}
				else if(tmp>=0)
				{
					flag=0;
				}
				ret._int.insert(0,1,tmp+'0');
				rt1++;
				rt2++;
			}
			while(rt1!=aa._int.rend())
			{
				int tmp=*rt1-flag-'0';
				if(tmp<0)
				{
					flag=1;
					tmp+=10;
				}
				else if(tmp>=0)
				{
					flag=0;
				}
				ret._int.insert(0,1,tmp+'0');
				rt1++;
			}
			ret=InputNum(ret._int+'.'+ret._float).second;
		}
		if(a._abs()>b._abs())		//处理符号位
			ret._sign=a._sign;
		else if(a._abs()<b._abs())
		{
			ret._sign=b._sign;
		}
		return ret;
	}

	Num reduce(Num& a,Num& b)
	{
		Num tb(b);
		if(a._sign==b._sign&&a._sign==POSITIVE)
		{
			tb._sign=NEGATIVE;
			return add(a,tb);
		}
		if(a._sign==b._sign&&a._sign==NEGATIVE)
		{
			tb._sign=POSITIVE;
			return add(a,tb);
		}
	}
	
	Num by(Num& a,Num&b)
	{
		Num ret;
		int pos1=a._float.length();
		int pos2=b._float.length();

		string s1,s2,s(1000,'0');
		s1=a._int+a._float;
		s2=b._int+b._float;

		reverse(s1.begin(),s1.end());  
        reverse(s2.begin(),s2.end());  
        for(int i=0;i<s1.length();i++)  
			for(int j=0;j<s2.length();j++)  
			{  
				int temp=(s1[i]-'0')*(s2[j]-'0');  
				s[i+j+1]=s[i+j+1]-'0'+(s[i+j]-'0'+temp)/10+'0';  
				s[i+j]=(s[i+j]-'0'+temp)%10+'0';  
			}
		reverse(s.begin(),s.end());  
		ret._int=s;
		int pos=s.length()-pos1-pos2+1;
		ret._int.resize(pos);
		ret._int[pos-1]='\0';

		int len=pos1+pos2;
		string::reverse_iterator rts=s.rbegin();
		while(rts!=s.rend()&&len>0)
		{
			ret._float.insert(0,1,*rts);
			rts++;
			len--;
		}

		if(a._sign==b._sign)
			ret._sign=POSITIVE;
		else 
			ret._sign=NEGATIVE;


		ret._int=ret.InputNum(ret._int).second._int;
		return ret;
	}

	Num except(Num& a,Num& b)
	{
		int len1=a._float.length();
		int len2=b._float.length();
		int _precision=a._pos;
		string aa=a._int+a._float;
		string bb=b._int+b._float;
		string tmp;
		string ans;
		Num cop1,cop2,ret;
		int ok=0;
		for(int i=0;i<len1;i++)
		{
		bb+='0';
		}
		for(int i=0;i<len2+_precision;i++)
		{
		aa+='0';
		}
		cop2._int=bb;
		for(int i=0;i<aa.size();i++)
		{
			tmp+=aa[i];
			cop1._int=tmp;
			if(cop1>=cop2)
			{
			ok=1;
			int ex=(_exc(tmp,bb));
			ans+=(ex+'0');
			//char arr[3]={0};
			//itoa(ex,arr,10);
			Num ttmp;
			ttmp._int+=ex+'0';
			tmp=reduce(cop1,by(cop2,ttmp))._int;
			}
			else/* if(ok==1)*/
			{
				ans+='0';
			}
		}

		string::iterator it=ans.begin();
		int intlen=ans.length()-_precision;
		while(it!=ans.end()&&intlen>0)
		{
			ret._int+=*it;
			it++;
			intlen--;
		}
		string::reverse_iterator rt1=ans.rbegin();
		while(_precision>0&&rt1!=ans.rend())
		{
			ret._float.insert(0,1,*rt1);
			rt1++;
			_precision--;
		}
		while(_precision>0)
		{
			ret._float.insert(0,1,'0');
			_precision--;
		}
		ret._int=InputNum(ret._int).second._int;
		return ret;
	}

	int _exc(string& a,string& b)
	{
		int len1=a.length();
		int len2=b.length();
		int ret=0;
		Num bb;
		Num tmp1,tmp2;
		bb._int=b;
		tmp1._int=a;
		tmp2._int=b;
		if(tmp1<tmp2)
			return 0;
		while(tmp1>=tmp2)
		{
			ret++;
			tmp2=tmp2.add(tmp2,bb);
		}
		return ret;
	}

	pair<bool,Num> InputNum(string& a)
	{
		string tmp;
		int point=0;
		int head=1;
		int flag=1;
		Num ret;
		string::iterator it=a.begin();
		if(a.empty())
			{
				return make_pair(true,ret);
			}
		while(it!=a.end())	//123 +123 -123 .123 0.123 0000.000123  +-=
		{
			if(*it=='-'&&head==1&&flag==1)
			{
				ret._sign=NEGATIVE;
				flag=0;
				it++;
				continue;
			}
			else if(*it=='+'&&head==1&&flag==1)
			{
				it++;
				flag=0;
				continue;
			}
			else if((*it=='+'||*it=='_')&&flag==0)
			{
				return make_pair(false,ret);
			}


			if(*it=='0'&&point==0&&head==1)
			{
			it++;
			continue;
			}

			if(*it=='.'&&point==0)
			{
			point=1;
			head=0;
			it++;
			continue;
			}
			else if(*it=='.'&&point==1)
			{
				return make_pair(false,ret);
			}

			if(*it>'9'||*it<'0')
			{
				return make_pair(false,ret);
			}

			if(*it<='9'&&*it>='0')
			{
				head=0;
				if(point==0)
				{
					ret._int+=*it;
					it++;
				}
				else if(point==1)
				{
					ret._float+=*it;
					it++;
				}
			}
		}
		return make_pair(true,ret);
	}

	friend ostream& operator<<(ostream& cout,Num& a);
}lfloat;

ostream& operator<<(ostream& cout,Num& a)
{
	if(a.IsZero(a))
	{
	cout<<"0";
	return cout;
	}
	if(a._int.empty()&&a._sign==NEGATIVE)
		cout<<"-0"<<'.'<<a._float;
	else if(a._int.empty()&&a._sign==POSITIVE)
		cout<<"0"<<'.'<<a._float;
	else if(a._sign==NEGATIVE)
		cout<<'-'<<a._int<<'.'<<a._float;
	else 
		cout<<a._int<<'.'<<a._float;
	return cout;
}
这样就得到了支持四则运算,支出修改除法精度的一个类 (lfloat)

下一篇优化乘法,缩减冗余代码,并实现运算表达式计算。

猜你喜欢

转载自blog.csdn.net/qq_15689151/article/details/79843139