高精度运算总结
作者:互联网
日期:2022年5月18日
注:本博客中的代码仅供参考。
概念
数据类型 | 定义标识符 | 数据范围 |
整型 | int | -231~231-1(≈2×109) |
长整型 | long long | -263~263-1 |
无符号长整型 | unsigned long long | 0~264-1 |
上面给出的范围的数称为单精度数,对应的运算称为单精度运算。
超出上面给出的范围的数称为高精度数(注:尝试使用这些范围存储的话会导致溢出),对应的运算称为高精度运算。
实现方法
将输入的数字导入某一数组(注:不同的数需要导入不同数组),并在该数组中模拟计算过程,最后将数组中的数字输出。
注:数组中的每一个位置应只存储一个位数的数字,否则在输出时可能会出现问题。
代码(正片【确信】)
高精度加法
#include<bits/stdc++.h> using namespace std; char s[510];//这个字符数组作为数据的“中转站”,最终将数据导入数组中 struct bigInt{ int length;//数据的长度(位数) int v[510];//存储数据的数组 }; bigInt operator +(bigInt a,bigInt b){//重新载入+ int k=max(a.length,b.length);//比较尾数大小,将更大的位数作为之后相加的长度 for(int i=1;i<=k;++i) { a.v[i]+=b.v[i];//将每一位的数相加 } for(int i=1;i<=k;++i)//进位 { a.v[i+1]+=a.v[i]/10; a.v[i]%=10; } if(a.v[k+1]) { ++k; }//如果最高位也存在进位,增加k的长度 //严格来说,应该检查不止一位。但因为加法最多会增加一位,所以检查与否都无足轻重,然而在高精度乘法中会显得尤为必要 a.length=k; return a; } bigInt A,B; int main(){ scanf("%s",s+1);//输入数据。s+1代表数据从s[1]向后存储 int n=strlen(s+1);//求数据的位数 for(int i=1;i<=n;++i) { A.v[i]=s[n-i+1]-'0';//赋值。-'0'可以使数据从字符转化为数字。倒过来存储有利于后面的计算(尤其是出现最高位进位时) } A.length=n;//赋值 scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;++i) { B.v[i]=s[n+1-i]-'0'; } B.length=n; A=A+B;//相加。这里的+使用的是重新载入的+ for(int i=A.length;i>=1;--i) { printf("%d",A.v[i]);//输出求得的和。由于数据是倒过来存储的,输出也应倒过来输出 } return 0; }
高精度减法
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=10186; 4 struct bigInt{ 5 int length; 6 int v[N]; 7 }; 8 bigInt A,B,C; 9 char s[N]; 10 bigInt read(){//用于读入数据的函数 11 memset(C.v,0,sizeof(C.v)); 12 scanf("%s",s+1); 13 int n=strlen(s+1); 14 for(int i=1;i<=n;++i) 15 { 16 C.v[i]=s[n+1-i]-'0'; 17 } 18 C.length=n; 19 return C; 20 } 21 bool operator >=(bigInt a,bigInt b){//比较两数大小 22 int m=a.length; 23 int n=b.length; 24 if(m>n)//当m与n位数不同时,位数更大的数更大 25 { 26 return true; 27 } 28 if(m<n) 29 { 30 return false; 31 } 32 for(int i=n;i>0;--i) 33 { 34 if(a.v[i]>b.v[i])//当位数相同时,从最高位向下遍历。如果某个数的某一位数字更大,则这个数更大 35 { 36 return true; 37 } 38 if(a.v[i]<b.v[i]) 39 { 40 return false; 41 } 42 } 43 return true; 44 } 45 bigInt operator -(bigInt a,bigInt b){ 46 int k=a.length; 47 for(int i=1;i<=k;++i) 48 { 49 if(a.v[i]<b.v[i]) 50 { 51 --a.v[i+1]; 52 a.v[i]+=10; 53 } 54 a.v[i]-=b.v[i]; 55 } 56 while(a.v[k]==0&&k>1) 57 { 58 --k; 59 } 60 a.length=k; 61 return a; 62 } 63 int main(){ 64 A=read(); 65 B=read(); 66 if(A>=B) 67 { 68 A=A-B; 69 }else{ 70 printf("-"); 71 A=B-A; 72 }//都是大的数减小的数,如果A<B时,在输出数据前面输出- 73 for(int i=A.length;i>0;--i) 74 { 75 printf("%d",A.v[i]); 76 }//同理,倒过来输出 77 return 0; 78 }
高精度乘法
1 #include<bits/stdc++.h> 2 using namespace std; 3 char s[2500]; 4 int result[4005]={0},rlength; 5 struct bigInt{ 6 int length; 7 int v[2500]; 8 }; 9 bigInt operator *(bigInt a,bigInt b){ 10 for(int i=1;i<=a.length;++i) 11 { 12 for(int j=1;j<=b.length;++j) 13 { 14 result[i+j-1]+=a.v[i]*b.v[j]; 15 } 16 } 17 for(int i=1;i<=4001;++i) 18 { 19 result[i+1]+=result[i]/10; 20 result[i]%=10; 21 } 22 rlength=a.length+b.length; 23 while(result[rlength]==0&&rlength>1) 24 { 25 --rlength; 26 }//乘法最高位可能不止进一位,但因为所得结果的最多位数为A的位数,B的位数,可以从最多位数开始向后遍历,在遇到不为0的数前且位数不为1时(考虑到结果为0的情况),将估计位数缩减 27 } 28 bigInt A,B; 29 int main(){ 30 scanf("%s",s+1); 31 int n=strlen(s+1); 32 for(int i=1;i<=n;++i) 33 { 34 A.v[i]=s[n+1-i]-'0'; 35 } 36 A.length=n; 37 scanf("%s",s+1); 38 n=strlen(s+1); 39 for(int i=1;i<=n;++i) 40 { 41 B.v[i]=s[n+1-i]-'0'; 42 } 43 B.length=n; 44 A=A*B; 45 for(int i=rlength;i>=1;--i) 46 { 47 printf("%d",result[i]); 48 } 49 return 0; 50 }
高精度除法
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=5100; 4 struct bigInt{ 5 int length; 6 int v[N]; 7 }; 8 bigInt operator /(bigInt a,long long b){ 9 int k=a.length; 10 long long res=0,c=0; 11 for(int i=k;i>=1;--i)//因为除法在计算时与+、-、×相反,且数据存储时依然是倒过来存储的,所以此处要从最高位开始运算 12 { 13 res=res*10+a.v[i]; 14 a.v[i]=res/b; 15 res%=b; 16 /*这里的原理是: 17 ①余数(res)乘10并加上下一位 18 ②将余数整除10的结果赋给要参加运算的那一位 19 ③余数取余10 20 */ 21 } 22 while(a.v[k]==0&&k>1) 23 { 24 --k;//统计位数 25 } 26 a.length=k; 27 return a; 28 } 29 bigInt A; 30 long long B; 31 char s[N]; 32 int main(){ 33 scanf("%s",s+1); 34 int n=strlen(s+1); 35 for(int i=1;i<=n;++i) 36 { 37 A.v[i]=s[n+1-i]-'0'; 38 } 39 A.length=n; 40 scanf("%lld",&B); 41 A=A/B; 42 for(int i=A.length;i>=1;--i) 43 { 44 printf("%d",A.v[i]); 45 } 46 return 0; 47 }
一些心得
- 使用高精度运算前要思考这道题是否需要高精度(如运算结果不会溢出就不需要用高精)/是否可以简化(如题目要求或可以推出是高精和单精——写了大半天高精和高精,结果最后发现是高精和单精的心情可不好)。如题目P1591(阶乘数码)中的阶乘就可以简化为高精乘单精。
- 在运算时也要注意开的一些数是否能完全囊括题目限定的数据范围。例如这段代码(星号处为要点):
1 bigInt operator /(bigInt a,long long b){ 2 int k=a.length; 3 *int res=0,c=0; 4 for(int i=k;i>=1;--i) 5 { 6 res=res*10+a.v[i]; 7 a.v[i]=res/b; 8 res%=b; 9 } 10 while(a.v[k]==0&&k>1) 11 { 12 --k; 13 } 14 a.length=k; 15 return a; 16 }
"int res=0,c=0;"会导致余数在超过范围时出现运算错误,如计算9000000000/1000000000的结果是0。正确的处理如下:
1 bigInt operator /(bigInt a,long long b){ 2 int k=a.length; 3 *long long res=0,c=0; 4 for(int i=k;i>=1;--i) 5 { 6 res=res*10+a.v[i]; 7 a.v[i]=res/b; 8 res%=b; 9 } 10 while(a.v[k]==0&&k>1) 11 { 12 --k; 13 } 14 a.length=k; 15 return a; 16 }
标签:总结,运算,高精度,int,res,long,--,length,bigInt 来源: https://www.cnblogs.com/PlayerSS05/p/16286352.html