高精度带符号整数算法

版权声明:原创文章版权归本文作者所有,转载文章版权归原作者所有,未经许可请勿转载! https://blog.csdn.net/Peter_Matthew/article/details/83142897

本博客是 高精度无符号整数算法 的延伸版本,请读者在食用前序文章后食用本篇效果更佳。

高精度的写法

同无符号的一样,我们仍采用struct封装,但与之前不同的是,我们新定义一个f表示正负。

struct Wint:vector<int>
{
	int f=1;
};

然后改下构造函数

    Wint(int n=0)
    {
    	if(n<0)n*=f=-1;
        push_back(n);
    }

不再过多解释构造函数写法,只是这里要判断收到的n的正负。
然后是check函数。

    Wint& check()
    {
        while(!empty()&&!back())pop_back();
        if(empty()){f=1;return *this;}
        if(back()<0)
        {
    		f*=-1;
    		for(int i=0; i<size(); ++i)
    			(*this)[i]*=-1;
        }
        for(int i=1; i<size(); ++i)
        {
        	while((*this)[i-1]<0)
	        {
	            int j=i;
	            while((*this)[j]<=0&&j<size())++j;
	            while(j>=i)
	            {
	                --(*this)[j];
	                (*this)[--j]+=10;
	            }
	        }
            (*this)[i]+=(*this)[i-1]/10;
            (*this)[i-1]%=10;
            while(!empty()&&!back())pop_back();
        	if(empty()){f=1;return *this;}
        }
        while(back()>=10)
        {
            push_back(back()/10);
            (*this)[size()-2]%=10;
        }
        if(back()<0)f*=-1,(*this)[size()-1]*=-1;
        return *this;
    }

那么整体的struct就长这样

struct Wint:vector<int>
{
	int f=1;
    Wint(int n=0)
    {
    	if(n<0)n*=f=-1;
        push_back(n);
    }
    Wint& check()
    {
        while(!empty()&&!back())pop_back();
        if(empty()){f=1;return *this;}
        if(back()<0)
        {
    		f*=-1;
    		for(int i=0; i<size(); ++i)
    			(*this)[i]*=-1;
        }
        for(int i=1; i<size(); ++i)
        {
        	while((*this)[i-1]<0)
	        {
	            int j=i;
	            while((*this)[j]<=0&&j<size())++j;
	            while(j>=i)
	            {
	                --(*this)[j];
	                (*this)[--j]+=10;
	            }
	        }
            (*this)[i]+=(*this)[i-1]/10;
            (*this)[i-1]%=10;
            while(!empty()&&!back())pop_back();
        	if(empty()){f=1;return *this;}
        }
        while(back()>=10)
        {
            push_back(back()/10);
            (*this)[size()-2]%=10;
        }
        if(back()<0)f*=-1,(*this)[size()-1]*=-1;
        return *this;
    }
};

所有的运算符重载可以参见我的 重载运算符和重载函数 博客

输入输出运算符

istream& operator>>(istream &is,Wint &n)
{
    string s;
    is>>s;
    n.clear();
    for(int i=s.size()-1; i>=0; --i)
    {
    	if(s[i]=='-')
    	{
    		n.f=-1;
    		continue;
    	}
    	n.push_back(s[i]-'0');
    }
    return is;
}
ostream& operator<<(ostream &os,const Wint &n)
{
    if(n.empty()){os<<0;return os;}
	if(n.f==-1)os<<"-";
    for(int i=n.size()-1; i>=0; --i)os<<n[i];
    return os;
}

直接增加"-"的判断即可。

关系运算符

正如之前的,我们只写高精度之间的比较~~,如果我们要比较一个高精度和另一个整数,可以同之前所述采用stringstream传(此条因太过毒瘤笔者被Diss到爆而去掉,感兴趣的读者可以自己了解下stringstream)~~。

bool operator!=(const Wint &a,const Wint &b)
{
	if(a.f!=b.f)return 1;
    if(a.size()!=b.size())return 1;
    for(int i=a.size()-1; i>=0; --i)
        if(a[i]!=b[i])return 1;
    return 0;
}
bool operator==(const Wint &a,const Wint &b)
{
    return !(a!=b);
}
bool operator<(const Wint &a,const Wint &b)
{
	if(a.f!=b.f)return a.f<b.f;
    if(a.size()!=b.size())return a.size()<b.size();
    for(int i=a.size()-1; i>=0; --i)
        if(a[i]!=b[i])return a[i]<b[i];
    return 0;
}
bool operator>(const Wint &a,const Wint &b)
{
    return b<a;
}
bool operator<=(const Wint &a,const Wint &b)
{
    return !(a>b);
}
bool operator>=(const Wint &a,const Wint &b)
{
    return !(a<b);
}

加上判断f即可。

单目运算符与abs函数

Wint operator-(Wint a)
{
	if(~a.f)a.f=-1;
	else a.f=1;
	return a.check();
} 
Wint abs(Wint a)
{
	if(a<0)return -a;
	else return a;
} 

对于-运算符,我们改变符号即可。
对于abs函数,我们分段返回即可。

逻辑运算符

此内容已因笔者过于蒟蒻或毒瘤而被Diss到爆炸,现已划线。

//bool operator!(Wint &n)
//{
//	n.check();
//	return n==0;
//}
//bool operator~(Wint &n)
//{
//	n.check();
//	return n!=-1;
//}
//bool operator&&(Wint &a,Wint &b)
//{
//	a.check();b.check();
//	if(!a)return 0;
//	if(!b)return 0;
//	return 1;
//}
//bool operator||(Wint &a,Wint &b)
//{
//	a.check();b.check();
//	if(a>0)return 1;
//	if(b>0)return 1;
//	return 0;
//}

即使加上符号也十分的简单对不对。。。

双目算术、赋值和自增自减运算符

Wint& operator+=(Wint &a,const Wint &b)
{
	Wint c=b;
    if(a.size()<c.size())a.resize(c.size());
    if(a<0&&c>0)
    {
    	if(abs(a)<abs(c))
    	{
    		swap(a,c);
    	}
    }
    else if(a>0&&c<0)
    {
    	if(abs(a)<abs(c))
    	{
    		swap(a,c);
    	}
    }
    for(int i=0; i!=b.size();++i)a[i]+=c[i]*((a.f==c.f)?1:-1);
    return a.check();
}
Wint operator+(Wint a,const Wint &b)
{
    return a+=b;
}
Wint& operator++(Wint &n)
{
	n+=1;
	return n.check();
}
Wint operator++(Wint &n,int flag)
{
	Wint tmp=n;
	n+=1;
	n.check();
	return tmp;
}
Wint& operator-=(Wint &a,const Wint b)
{
	return a+=-b;
}
Wint operator-(Wint a,const Wint &b)
{
    return a-=b;
}
Wint& operator--(Wint &n)
{
	n-=1;
	return n.check();
}
Wint operator--(Wint &n,int flag)
{
	Wint tmp=n;
	n-=1;
	n.check();
	return tmp;
}

有了符号,加减就可以一起处理了。

Wint operator*(const Wint &a,const Wint &b)
{
    Wint n;
    if(a.f!=b.f)n.f=-1;
    else n.f=1;
    n.assign(a.size()+b.size()-1,0);
    for(int i=0; i!=a.size(); ++i)
        for(int j=0; j!=b.size(); ++j)
            n[i+j]+=a[i]*b[j];
    return n.check();
}
Wint& operator*=(Wint &a,const Wint &b)
{
    return a=a*b;
}
Wint divmod(Wint &a,const Wint &b)
{
    Wint ans,tmp=b;
    int af=a.f,tmpf=tmp.f;
    a.f=tmp.f=1;
    for(int t=a.size()-tmp.size(); a>=tmp; --t)
    {
        Wint d;
        d.assign(t+1,0);
        d.back()=1;
        Wint c=tmp*d;
        while(a>=c)
        {
            a-=c;
            ans+=d;
        }
    }
    if(af!=tmpf)ans.f=-1;
    else ans.f=1;
    a.f=af,tmp.f=tmpf;
    return ans.check();
}
Wint operator/(Wint a,const Wint &b)
{
    return divmod(a,b);
}
Wint& operator/=(Wint &a,const Wint &b)
{
    return a=a/b;
}
Wint& operator%=(Wint &a,const Wint &b)
{
    divmod(a,b);
    return a;
}
Wint operator%(Wint a,const Wint &b)
{
    return a%=b;
}

乘除只用判断同或异号。
这里的取模运算,对于正数,取正或负模均为正数;对于负数,取正或负模均为负数。

常用函数

abs函数已经在上文提过。

Wint pow(const Wint &n,const Wint &k)
{
    if(k.empty())return 1;
    if(k==2)return n*n;
    if(k.back()%2)return n*pow(n,k-1);
    return pow(pow(n,k/2),2);
}
//下面是非递归写法
Wint pow(Wint n,Wint k)
{
	Wint ans(1);
	while(k>0)
	{
		if(k%2>0)
			ans*=n;
		n*=n;
		k/=2;
	}
	return ans;
}

这是快速幂函数。

回顾

那么整体的写法如下

struct Wint:vector<int>
{
	int f=1;
    Wint(int n=0)
    {
    	if(n<0)n*=f=-1;
        push_back(n);
    }
    Wint& check()
    {
        while(!empty()&&!back())pop_back();
        if(empty()){f=1;return *this;}
        if(back()<0)
        {
    		f*=-1;
    		for(int i=0; i<size(); ++i)
    			(*this)[i]*=-1;
        }
        for(int i=1; i<size(); ++i)
        {
        	while((*this)[i-1]<0)
	        {
	            int j=i;
	            while((*this)[j]<=0&&j<size())++j;
	            while(j>=i)
	            {
	                --(*this)[j];
	                (*this)[--j]+=10;
	            }
	        }
            (*this)[i]+=(*this)[i-1]/10;
            (*this)[i-1]%=10;
            while(!empty()&&!back())pop_back();
        	if(empty()){f=1;return *this;}
        }
        while(back()>=10)
        {
            push_back(back()/10);
            (*this)[size()-2]%=10;
        }
        if(back()<0)f*=-1,(*this)[size()-1]*=-1;
        return *this;
    }
};
istream& operator>>(istream &is,Wint &n)
{
    string s;
    is>>s;
    n.clear();
    for(int i=s.size()-1; i>=0; --i)
    {
    	if(s[i]=='-')
    	{
    		n.f=-1;
    		continue;
    	}
    	n.push_back(s[i]-'0');
    }
    return is;
}
ostream& operator<<(ostream &os,const Wint &n)
{
    if(n.empty()){os<<0;return os;}
	if(n.f==-1)os<<"-";
    for(int i=n.size()-1; i>=0; --i)os<<n[i];
    return os;
}
bool operator!=(const Wint &a,const Wint &b)
{
	if(a.f!=b.f)return 1;
    if(a.size()!=b.size())return 1;
    for(int i=a.size()-1; i>=0; --i)
        if(a[i]!=b[i])return 1;
    return 0;
}
bool operator==(const Wint &a,const Wint &b)
{
    return !(a!=b);
}
bool operator<(const Wint &a,const Wint &b)
{
	if(a.f!=b.f)return a.f<b.f;
    if(a.size()!=b.size())return a.size()<b.size();
    for(int i=a.size()-1; i>=0; --i)
        if(a[i]!=b[i])return a[i]<b[i];
    return 0;
}
bool operator>(const Wint &a,const Wint &b)
{
    return b<a;
}
bool operator<=(const Wint &a,const Wint &b)
{
    return !(a>b);
}
bool operator>=(const Wint &a,const Wint &b)
{
    return !(a<b);
}
Wint operator-(Wint a)
{
	if(~a.f)a.f=-1;
	else a.f=1;
	return a.check();
} 
Wint abs(Wint a)
{
	if(a<0)return -a;
	else return a;
} 
Wint& operator+=(Wint &a,const Wint &b)
{
	Wint c=b;
    if(a.size()<c.size())a.resize(c.size());
    if(a<0&&c>0)
    {
    	if(abs(a)<abs(c))
    	{
    		swap(a,c);
    	}
    }
    else if(a>0&&c<0)
    {
    	if(abs(a)<abs(c))
    	{
    		swap(a,c);
    	}
    }
    for(int i=0; i!=b.size();++i)a[i]+=c[i]*((a.f==c.f)?1:-1);
    return a.check();
}
Wint operator+(Wint a,const Wint &b)
{
    return a+=b;
}
Wint& operator++(Wint &n)
{
	n+=1;
	return n.check();
}
Wint operator++(Wint &n,int flag)
{
	Wint tmp=n;
	n+=1;
	n.check();
	return tmp;
}
Wint& operator-=(Wint &a,const Wint b)
{
	return a+=-b;
}
Wint operator-(Wint a,const Wint &b)
{
    return a-=b;
}
Wint& operator--(Wint &n)
{
	n-=1;
	return n.check();
}
Wint operator--(Wint &n,int flag)
{
	Wint tmp=n;
	n-=1;
	n.check();
	return tmp;
}
Wint operator*(const Wint &a,const Wint &b)
{
    Wint n;
    if(a.f!=b.f)n.f=-1;
    else n.f=1;
    n.assign(a.size()+b.size()-1,0);
    for(int i=0; i!=a.size(); ++i)
        for(int j=0; j!=b.size(); ++j)
            n[i+j]+=a[i]*b[j];
    return n.check();
}
Wint& operator*=(Wint &a,const Wint &b)
{
    return a=a*b;
}
Wint divmod(Wint &a,const Wint &b)
{
    Wint ans,tmp=b;
    int af=a.f,tmpf=tmp.f;
    a.f=tmp.f=1;
    for(int t=a.size()-tmp.size(); a>=tmp; --t)
    {
        Wint d;
        d.assign(t+1,0);
        d.back()=1;
        Wint c=tmp*d;
        while(a>=c)
        {
            a-=c;
            ans+=d;
        }
    }
    if(af!=tmpf)ans.f=-1;
    else ans.f=1;
    a.f=af,tmp.f=tmpf;
    return ans.check();
}
Wint operator/(Wint a,const Wint &b)
{
    return divmod(a,b);
}
Wint& operator/=(Wint &a,const Wint &b)
{
    return a=a/b;
}
Wint& operator%=(Wint &a,const Wint &b)
{
    divmod(a,b);
    return a;
}
Wint operator%(Wint a,const Wint &b)
{
    return a%=b;
}
Wint pow(const Wint &n,const Wint &k)
{
    if(k.empty())return 1;
    if(k==2)return n*n;
    if(k.back()%2)return n*pow(n,k-1);
    return pow(pow(n,k/2),2);
}
////下面是非递归写法
//Wint pow(Wint n,Wint k)
//{
//	Wint ans(1);
//	while(k>0)
//	{
//		if(k%2>0)
//			ans*=n;
//		n*=n;
//		k/=2;
//	}
//	return ans;
//}

高精度的用法

还是举洛谷高精度算法试炼场中的几道题
我们在main函数中这么写

int main()
{
    Wint a,b;
    //可以把b改成int型,仍能正常使用(题切不了)
    cin>>a>>b;
    //LuoguP1601 cout<<a+b<<endl;
    //LuoguP2142 cout<<a-b<<endl;
    //LuoguP1303 cout<<a*b<<endl;
    return 0;
}

知识共享许可协议

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

猜你喜欢

转载自blog.csdn.net/Peter_Matthew/article/details/83142897