高精度数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; }