高精度加、减及混合
我们知道,减法在本质上其实是加法,就是把数字前的负号当成这个数字的组成部分
那么,如何实现真正的高精度加法呢(即需要考虑负数的情况)?
一步一步来吧!
PART1:
有两个很大的非负整数,大概有10^1000的位数那么大,求和?
这就是很纯的高精度加法,即不用考虑负数的情况,实现如下:
1 void add(BigNum *x,BigNum *y,BigNum *z){ 2 z->len=max(x->len,y->len); 3 for(int i=1;i<=z->len;i++){ 4 z->s[i]+=x->s[i]+y->s[i]; 5 z->s[i+1]=z->s[i]/10; 6 z->s[i]%=10; 7 } 8 if(z->s[z->len+1]) z->len++; 9 }
说明一下,以下部分也一样
我们开了个结构体BigNum储存大整数的长度、其本身和符号:
1 struct BigNum{ 2 int s[maxn],len,f; 3 BigNum(){len=0;f=1;memset(s,0,sizeof(s));}//为重构函数,这样可以在声明变量的时候就把变量初始化 4 };
x、y为拿来操作的两个大整数,z为结果
这里用的指针,传给函数的是大整数的地址,可以直接修改对应的大整数,操作起来会比较方便
PART2:
有两个很大的非负整数,大概有10^1000的位数那么大,被减数有可能小于减数,求差?
这就是所谓的高精减
因为不保证被减数不小于减数,所以需要多进行一步判z的符号的操作,实现如下:
1 void subtract(BigNum *x,BigNum *y,BigNum *z){//符号确定后差的值就是大数减小数 2 for(int i=1;i<=x->len;i++){ 3 z->s[i]=x->s[i]-y->s[i]; 4 if(z->s[i]<0){ 5 x->s[i+1]--; 6 z->s[i]+=10; 7 } 8 } 9 int o=x->len; 10 while(o>1&&!z->s[o]) o--; 11 z->len=o; 12 } 13 void sub(BigNum *x,BigNum *y,BigNum *z){//判断差的符号 14 if(x->len<y->len){ 15 z->f=-1; 16 subtract(y,x,z); 17 } 18 else if(x->len==y->len){ 19 for(int i=x->len;i>0;i--) 20 if(x->s[i]<y->s[i]){ 21 z->f=-1; 22 subtract(y,x,z); 23 return; 24 } 25 subtract(x,y,z); 26 } 27 else subtract(x,y,z); 28 }
RART3:
有两个很大的整数,大概有10^1000的位数那么大,求和?
这就是我们的目的所在
其实就是把以上的做法结合起来
除此之外,开始处理之前还需要再加一步对输入大整数符号的判断,好分配接下来的工作
完整代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #define maxn 2333 5 using namespace std; 6 struct BigNum{ 7 int s[maxn],len,f; 8 BigNum(){len=0;f=1;memset(s,0,sizeof(s));}//为重构函数,这样可以在声明变量的时候就把变量初始化 9 }; 10 char ai[maxn],bi[maxn]; 11 BigNum a,b,c; 12 void add(BigNum*,BigNum*,BigNum*); 13 void subtract(BigNum*,BigNum*,BigNum*); 14 void sub(BigNum*,BigNum*,BigNum*); 15 void allot(BigNum*,BigNum*,BigNum*); 16 int main(){ 17 scanf(" %s %s",ai,bi); 18 a.len=strlen(ai); 19 b.len=strlen(bi); 20 for(int i=a.len-1;i>0;i--) a.s[a.len-i]=ai[i]-'0'; 21 for(int i=b.len-1;i>0;i--) b.s[b.len-i]=bi[i]-'0'; 22 if(ai[0]=='-'){ 23 a.f=-1;a.len--; 24 } 25 else a.s[a.len]=ai[0]-'0'; 26 if(bi[0]=='-'){ 27 b.f=-1;b.len--; 28 } 29 else b.s[b.len]=bi[0]-'0'; 30 allot(&a,&b,&c); 31 if(c.f<0) putchar('-'); 32 for(int i=c.len;i>0;i--) printf("%d",c.s[i]); 33 return 0; 34 } 35 void allot(BigNum *x,BigNum *y,BigNum *z){ //判断所输入大整数需要进行何种计算 36 if(x->f<0&&y->f<0){ 37 z->f=-1; 38 add(x,y,z); 39 } 40 else if(x->f>0&&y->f>0) add(x,y,z); 41 else if(x->f>0&&y->f<0) sub(x,y,z); 42 else sub(y,x,z); 43 } 44 void add(BigNum *x,BigNum *y,BigNum *z){ 45 z->len=max(x->len,y->len); 46 for(int i=1;i<=z->len;i++){ 47 z->s[i]+=x->s[i]+y->s[i]; 48 z->s[i+1]=z->s[i]/10; 49 z->s[i]%=10; 50 } 51 if(z->s[z->len+1]) z->len++; 52 } 53 void subtract(BigNum *x,BigNum *y,BigNum *z){//符号确定后差的值就是大数减小数 54 for(int i=1;i<=x->len;i++){ 55 z->s[i]=x->s[i]-y->s[i]; 56 if(z->s[i]<0){ 57 x->s[i+1]--; 58 z->s[i]+=10; 59 } 60 } 61 int o=x->len; 62 while(o>1&&!z->s[o]) o--; 63 z->len=o; 64 } 65 void sub(BigNum *x,BigNum *y,BigNum *z){//判断差的符号 66 if(x->len<y->len){ 67 z->f=-1; 68 subtract(y,x,z); 69 } 70 else if(x->len==y->len){ 71 for(int i=x->len;i>0;i--) 72 if(x->s[i]<y->s[i]){ 73 z->f=-1; 74 subtract(y,x,z); 75 return; 76 } 77 subtract(x,y,z); 78 } 79 else subtract(x,y,z); 80 }