填坑行动1-高精度运算


拖更很久了

Update8.12:更改了一些错误的地方

前置芝士-运算符重载

例子

看下边的代码:

#inclue<iostream>
using namespace std;
int main(){
	int a,b;
	cin>>a>>b;
	cout<<a+b;
}

cin>>a>>b在这里是指输入两个数 a , b a,b a,b,就有人会问了,>>不是右移吗?怎么用来输入变量了?其实这就是一个简单的运算符重载。

方法

那么我们改怎么重载呢?

类型 operator 符号(参数) const {
	内容(记得带返回值)
}

其中const是要在结构体里面定义的时候才加。
可以重载的符号有:

new delete new[] delete[]
+ - * / % ^ & & | ~
! = < > += -=  *= /= %=
^= &= |= << >> >>= <<=
== != <= >=  &&  || ++
-- , ->* -> () []

其中[]指下标,
可以有两个参数,也可以有一个参数的有:

+ - * &

当然,重载流输流输出有不一样的格式,这是友元函数:

friend istream & operator >> (istream &,bigint &x){
	...
	return cin;
}
friend ostream & operator <<(ostream &,bigint x){
	...
	return cout;
}

高精度运算

存储

有些时候进行运算的时候,数字会很大,导致int_128都装不下,不如自己动手,丰衣足食,自己定义一种变量,满足进行很大的数字的运算。这里叫bigint
那么,bigint里面要有什么东西呢?我们先看一下short是怎么存贮的:主要是int有32位画不下
在这里插入图片描述
我们就可以定义一个数组,数组的每一位,代表每一个数。还有两个变量,一个代表长度,一个代表正负,就是这样:

struct bigint{
	int len,flag;//flag 1 fu 0 zheng 
	int a[maxn];
}
输入输出&&运算原理

然后考虑怎么运算,其实很简单,就像小学生一样做竖式运算就可以了,为了方便进行运算,令 a 1 a_1 a1为个位, a 2 a_2 a2为十位, a 3 a_3 a3为百位,以此类推即可。
然后考虑怎么输入,我们发现,输入的是一个很大的数字,不能直接用cin,为了一次性读入,我们读入一个字符串 s s s,不难得到 a i = s l e n − i a_i=s_{len-i} ai=sleni,最后删去前导零,比如说 0001 0001 0001要写成 1 1 1
输出只要倒着输出就可以了。一个for循环搞定。记得注意符号。
奉上输入输出重载:

	friend istream & operator >> (istream &,bigint &x){
		char s[maxn]; cin>>s;
		x.len=strlen(s);
		if(s[0]=='-') x.flag=1;
		memset(x.a,0,sizeof(x.a));
		if(x.flag)
		    for(register int i=1;i<x.len;i++) 
	            x.a[i]=s[x.len-i]^48;
	    else for(register int i=1;i<=x.len;i++) 
	            x.a[i]=s[x.len-i]^48;
	    for(;x.len>1;x.len--)
	        if(x.a[x.len]!=0)
	        	break;//删去前导零 
	    return cin;
	}
	friend ostream & operator <<(ostream & ,bigint x){
		if(x.flag) printf("-");
		int flag=0;
		for(register int i=x.len;i>=1;i--){
			if(x.a[i]>0) flag=1;
			if(flag)
		    	printf("%d",x.a[i]);
		}
		if(!flag) putchar('0');
		return cout;
	}
加减

加减只要按照竖式法从低到高加就可以了,还要注意进位,算法复杂度 Θ ( n ) \Theta(n) Θ(n)
注意正负就可以了。(初中老师应该讲过有理数的加减的吧)

乘除

乘法依旧是竖式计算,不过正负的处理更加简单。
注意 a i × b j a_i\times b_j ai×bj的结果应该储存在 a n s i + j − ‘ ans_{i+j-`} ansi+j中,注意ans.len=a.len+b.len-1或者ans.len=a.len+b.len
除法也可以用竖式解决,这里暂时不涉及。

代码

最后献上代码。据说很多人喜欢这个

struct bigint{
	int len,flag;//flag 1 fu 0 zheng 
	int a[maxn];
	bigint (*intit)(int);
	void (*check)(bigint);
	friend istream & operator >> (istream &,bigint &x){
		char s[maxn]; cin>>s;
		x.len=strlen(s);
		if(s[0]=='-') x.flag=1;
		memset(x.a,0,sizeof(x.a));
		if(x.flag)
		    for(register int i=1;i<x.len;i++) 
	            x.a[i]=s[x.len-i]^48;
	    else for(register int i=1;i<=x.len;i++) 
	            x.a[i]=s[x.len-i]^48;
	    for(;x.len>1;x.len--)
	        if(x.a[x.len]!=0)
	        	break;//ɾȥǰµ¼Áã 
	    return cin;
	}
	friend ostream & operator <<(ostream & ,bigint x){
		if(x.flag) printf("-");
		int flag=0;
		for(register int i=x.len;i>=1;i--){
			if(x.a[i]>0) flag=1;
			if(flag)
		    	printf("%d",x.a[i]);
		}
		if(!flag) putchar('0');
		return cout;
	}
	bool operator > (const bigint &x)const{
		if(!x.flag&&!this->flag){
			if(this->len > x.len ) return true;
			if(this->len < x.len ) return false;
			for(int i=x.len;i>=1;i--)
			    if( this->a[i] > x.a[i] ) return true;
			    else if( this->a[i] < x.a[i] ) return false;
		}
		if(this->flag&&!x.flag) return false;
		if(!this->flag&&x.flag) return true;
		
		if(this->len < x.len ) return true;
		if(this->len > x.len ) return false;
		for(int i=x.len;i>=1;i--)
		    if( this->a[i] < x.a[i] ) return true;
			else if( this->a[i] > x.a[i] ) return false;
		return false;
	}
	bool operator == (const bigint &x)const{
		if(x.flag!=this->flag) return 0;
		for(int i=1;i<=max(x.len,this->len);i++)
		    if(x.a[i]!=this->a[i])
		        return 0;
		return 1;
	}
	bool operator < (const bigint &x) const { return !(*this>=x); }
	bool operator <= (const bigint &x) const { return !(*this>x); }
	bool operator >= (const bigint &x) const { return *this>x || *this==x;}
	bigint operator +(const bigint &x) const {
		bigint ans=(bigint){0,0,{}};
		int jw=0;
		if(this->flag==x.flag){
			ans.flag=x.flag;
			ans.len=max(this->len,x.len);
			for(int i=1;i<=ans.len;i++)
			    if(this->a[i]+x.a[i]+jw>=10){
			    	ans.a[i]=(this->a[i]+x.a[i]+jw)-10;
			    	jw=1;
				}
				else{
					ans.a[i]=(this->a[i]+x.a[i]+jw);
			    	jw=0;
				}
			if(jw==1){ ans.len++; ans.a[ans.len]=1; }
			return ans;
		}
		bigint thi;
		int flag,tw;
		if(this->flag==1&&x.flag==0){
			memset(thi.a,0,sizeof(thi.a));
		    for(int i=1;i<=x.len;i++)
				thi.a[i]=this->a[i];
			thi.flag=0;
			thi.len=this->len;
			if(thi>x){
				ans.flag=1;
				for(int i=1;i<=thi.len;i++)
					if(thi.a[i]-tw-x.a[i]<0){
						ans.a[i]=thi.a[i]-tw-x.a[i]+10;
						tw=1;
					}
					else{
						ans.a[i]=thi.a[i]-tw-x.a[i];
						tw=0;
					}
				ans.len=thi.len;
			}
			else{
				ans.flag=0;
				for(int i=1;i<=x.len;i++)
					if(x.a[i]-tw-thi.a[i]<0){
						ans.a[i]=x.a[i]-tw-thi.a[i]+10;
						tw=1;
					}
					else{
						ans.a[i]=x.a[i]-tw-thi.a[i];
						tw=0;
					}
				ans.len=x.len;
			}
		}
		if(this->flag==0&&x.flag==1){
			memset(thi.a,0,sizeof(thi));
			for(int i=1;i<=x.len;i++)
				thi.a[i]=x.a[i];
			thi.flag=0; thi.len=x.len;
			if(*this>=thi){
				ans.flag=0; ans.len=this->len;
				for(int i=1;i<=ans.len;i++)
					if(this->a[i]-tw-thi.a[i]<0){
						ans.a[i]=this->a[i]-tw-thi.a[i]+10;
						tw=1;
					}
					else{
						ans.a[i]=this->a[i]-tw-thi.a[i];
						tw=0;
					}
			}
			else{
				ans.flag=1; ans.len=thi.len;
				for(int i=1;i<=ans.len;i++)
					if(thi.a[i]-tw-this->a[i]<0){
						ans.a[i]=thi.a[i]-tw-this->a[i]+10;
						tw=1;
					}
					else{
						ans.a[i]=thi.a[i]-tw-this->a[i];
						tw=0;
					}
			}
		}
		while(ans.len>1&&ans.a[ans.len]==1) ans.len--;
		return ans;
	}
	bigint  operator -(const bigint &x) const {
		bigint thi;
		memset(thi.a,0,sizeof(thi.a));
		thi.len=x.len;
		for(int i=1;i<=x.len;i++)
			thi.a[i]=x.a[i];
		thi.flag=!x.flag;
		return *this+thi;
	}
	bigint operator *(bigint &x){
		bigint ans=(bigint){0,0,{0}};
		for(register int i=1;i<=x.len;i++)
		    for(register int j=1;j<=this->len;j++){
		    	ans.a[i+j-1]+=this->a[j]*x.a[i];
		    	ans.a[i+j]+=ans.a[i+j-1]/10;
		    	ans.a[i+j-1]%=10;
			}
		ans.len=this->len+x.len+1;
		ans.flag=(this->flag)^(x.flag);
		while(ans.a[ans.len]==0&&ans.len>1) ans.len--;
		return ans;
	}
};
bigint intit(int x){
	bigint ans=(bigint){0,0,{0}};
	if(x<0){
		x=-x;
		ans.flag=1;
	}
	if(x==0){
		ans.len=1;
		return ans;
	}
	while(x>0){
		ans.a[++ans.len]=x%10;
		x/=10;
	}
	return ans;
}

记得定义maxn的大小哦~~~(maxn是位数)
这里重载了 >> << + - * > < >= <= ==
bigint init(int)是把一个int类型的数转化成bigint类型。
完结撒花

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值