NOIP学习小站
西安交通大学附属中学航天学校

高精度运算——高精度正整数减法

高精度数A-高精度数B,如果A>=B,那么直接从低位到高位按位相减即可,需要额外处理不够减时的借位情况;如果A<B,则结果是-(B-A)。可知高精度减法,只需要考虑较大数减去较小数的情况,如果较小数减去较大数,那么可以先输出负号,仍然输出较大数减去较小数的结果。

通过上面的分析可知,需要先考虑如何判断两个高精度正整数的大小。如果两个数的位数不等,那么位数大的那个数大;如果位数相等,那就应该从高位到低位依次判断每位上的数字:

/* 比较高精度数ma和mb的大小
** ma>mb返回1,ma=mb返回0,ma<mb返回-1 
**/
int compare(int ma[],int mb[]){
	if(ma[0]>mb[0]){			//ma位数高于mb 
		return 1;
	}else if(ma[0]==mb[0]){	 //ma位数等于mb
		//从高到低每位都判断 
		for(int i=ma[0];i>=1;i--){
			if(ma[i]>mb[i]) return 1;
			else if(ma[i]<mb[i]) return -1;
		}
		//所有位判断结束,之前没有return,那么两个高精度正整数肯定相等 
		return 0;
	}else{					  //ma位数低于mb 
		return -1;
	}
}

高精度相减,从低位到高位按位相减,并处理不够减时借位的情况:

/* 高精度减法 
** ma-mb → mc 
** 前提:ma>=mb
**/
void minus(int ma[],int mb[],int mc[]){	
	mc[0] = ma[0];	//结果的位数
	
	int x = 0;		//借位 
	//从低位到高位按位相减 
	for(int i=1;i<=ma[0];i++){
		mc[i] = ma[i]-mb[i]-x;	//从低位到高位按位相减(考虑了借位)  
		if(mc[i]<0){			  //从高位借位 
			mc[i]+=10;
			x = 1;
		}else{					//不需要借位 
			x = 0;
		}
	}
}

上面的减法还存在一个BUG,那就是相减后高位可能出现大量多余的0,看下面的例子:

可以使用一个函数来处理高精度数高位多余的0:

/* 过滤掉高位多余的0 
**/ 
void modify(int arr[]){ 
	while(arr[arr[0]]==0 && arr[0]>1) arr[0]--;
}

/* 高精度减法 
** ma-mb → mc 
** 前提:ma>=mb
**/
void minus(int ma[],int mb[],int mc[]){	
	mc[0] = ma[0];	//结果的位数
	
	int x = 0;		//借位 
	//从低位到高位按位相减 
	for(int i=1;i<=ma[0];i++){
		mc[i] = ma[i]-mb[i]-x;	//从低位到高位按位相减(考虑了借位)  
		if(mc[i]<0){			  //从高位借位 
			mc[i]+=10;
			x = 1;
		}else{					//不需要借位 
			x = 0;
		}
	}
	//过滤掉高位多余的0 
	modify(mc);
}

高精度自减也不难实现:

/* 高精度自减
** ma-mb → ma
** 前提:ma>=mb
**/ 
void minus(int ma[],int mb[]){
	int x = 0;	//借位	
	//从低位到高位按位相减 
	for(int i=1;i<=ma[0];i++){
		ma[i] = ma[i]-mb[i]-x;	//从低位到高位按位相减(考虑了借位)  
		if(ma[i]<0){			  //从高位借位 
			ma[i]+=10;
			x = 1;
		}else{					//不需要借位 
			x = 0;
		}
	}
	
	//过滤掉高位多余的0 
	modify(ma);
}

完整的测试程序如下:

#include<cstdio>
#include<cstring>
#define N 10010
char s1[N],s2[N];
int a[N],b[N],c[N];

/***********************************************************************
** 函数申明
***********************************************************************/
void convert(char s[],int arr[]);		//高精度整数字符串格式化存储到数组 
void print(int arr[]);				   //输出存储在数组中的高精度整数

void modify(int arr[]);				  //过滤掉高位多余的0
int compare(int ma[],int mb[]);		  //比较高精度数ma和mb的大小

void minus(int ma[],int mb[],int mc[]);	//高精度减法 ma-mb →mc 前提:ma>=mb
void minus(int ma[],int mb[]);			 //高精度自减 ma-mb →ma 前提:ma>=mb
/**********************************************************************/
//函数申明结束


/* 高精度正整数字符串格式化存储到数组
** arr[0]保存数字位数
** arr[1],arr[2],...,arr[arr[0]]从低位到高位依次存储高精度整数 
**/
void convert(char s[],int arr[]){ 
	memset(arr,0,N*sizeof(int));		//数组arr全部元素初始化为0 
	for(int i=strlen(s)-1;i>=0;i--){
		arr[0]++;
		arr[arr[0]] = s[i]-'0';
	}
	modify(arr);
}

/* 输出存储在数组中的高精度整数 
**/ 
void print(int arr[]){
	for(int i=arr[0];i>=1;i--) printf("%d",arr[i]);
}

/* 过滤掉高位多余的0 
**/ 
void modify(int arr[]){ 
	while(arr[arr[0]]==0 && arr[0]>1) arr[0]--;
}

/* 比较高精度数ma和mb的大小
** ma>mb返回1,ma=mb返回0,ma<mb返回-1 
**/
int compare(int ma[],int mb[]){
	if(ma[0]>mb[0]){			//ma位数高于mb 
		return 1;
	}else if(ma[0]==mb[0]){	 //ma位数等于mb
		//从高到低每位都判断 
		for(int i=ma[0];i>=1;i--){
			if(ma[i]>mb[i]) return 1;
			else if(ma[i]<mb[i]) return -1;
		}
		//所有位判断结束,之前没有return,那么两个高精度正整数肯定相等 
		return 0;
	}else{					  //ma位数低于mb 
		return -1;
	}
}

/* 高精度减法 
** ma-mb → mc 
** 前提:ma>=mb
**/
void minus(int ma[],int mb[],int mc[]){	
	mc[0] = ma[0];	//结果的位数
	
	int x = 0;		//借位 
	//从低位到高位按位相减 
	for(int i=1;i<=ma[0];i++){
		mc[i] = ma[i]-mb[i]-x;	//从低位到高位按位相减(考虑了借位)  
		if(mc[i]<0){			  //从高位借位 
			mc[i]+=10;
			x = 1;
		}else{					//不需要借位 
			x = 0;
		}
	}
	//过滤掉高位多余的0 
	modify(mc);
}

/* 高精度自减
** ma-mb → ma
** 前提:ma>=mb
**/ 
void minus(int ma[],int mb[]){
	int x = 0;	//借位	
	//从低位到高位按位相减 
	for(int i=1;i<=ma[0];i++){
		ma[i] = ma[i]-mb[i]-x;	//从低位到高位按位相减(考虑了借位)  
		if(ma[i]<0){			  //从高位借位 
			ma[i]+=10;
			x = 1;
		}else{					//不需要借位 
			x = 0;
		}
	}
	
	//过滤掉高位多余的0 
	modify(ma);
}

int main()
{
	//将高精度正整数按照字符串的方式输入存储 
	scanf("%s%s",s1,s2);
	
	//遵循存储规则,得到存储高精度正整数的数组 
	convert(s1,a);
	convert(s2,b);
	
	printf("输入的第1个高精度正整数是:\n");
	print(a);	
	printf("\n\n");
	
	printf("输入的第2个高精度正整数是:\n");
	print(b);	
	printf("\n\n");
	
	printf("第1个数-第2个数的结果是:\n");
	int r = compare(a,b);	//比较两个正整数的大小 
	if(r>=0){
		minus(a,b,c);
	}else{
		minus(b,a,c);
		printf("-");
	}
	print(c);
	return 0;
}