思想:
先用字符串来读入大整数,然后用数组来存储大整数。与上一篇的所讲思路不同的是,这次是数组的每一个元素对应大整数的一个数,从而模拟手算过程。
主要实现思路与手算无太大差别。主要是一些细节上。
统一做个说明:模拟大数的数组的第零个元素保存的是数字个数(不包括第零个元素),而且数组从1到尾分别存大数的低位到高位,刚好相反。
在运算过程中的对齐操作全以此为标准。
读入时统一处理:
1 memset(a,0,sizeof(a)); 2 memset(b,0,sizeof(b)); 3 cin >> s >> t;//输入两个大数到字符串中 4 a[0] = s.length();//存储字符串s元素的个数,即大数a的位数 5 for(int i = 1;i<=a[0];i++)//并转化为整数存储在数组a中的对应位置 6 { 7 a[i] = s[a[0]-i]-'0'; 8 } 9 b[0] = t.length();//存储字符串t的个数,即大数b的位数 10 for(int i = 1;i<=b[0];i++)//并转化为整数存储在数组b中的对应位置 11 { 12 b[i] = t[b[0]-i]-'0'; 13 }
高精度加法:
1 void add(int* a,int* b) 2 { 3 len = max(a[0],b[0]); 4 for(int i = 1;i<=len;i++) 5 { 6 a[i] = a[i]+b[i]; 7 a[i+1] += a[i]/10;//进位 8 a[i] %= 10; 9 } 10 len++;//去除前导零 11 while(a[len]==0&&len>1) 12 { 13 len--; 14 } 15 for(int i = len;i>0;i--) 16 { 17 cout << a[i]; 18 } 19 cout << endl; 20 }
高精度减法:
减法的特别之处在于两个数的大小不确定,那我们就先比较两个数的大小,保证用大的数减去小的数,结果分类看是否加负号。
1 int larger(string s,string t) //看s是否>=t 2 { 3 if(s.length()!=t.length()) 4 { 5 return s.length()>t.length();//长度不同长的大 6 } 7 for(int i = 0;i<s.length();i++) 8 { 9 if(s[i]!=t[i]) 10 { 11 return s[i]>t[i];//长度相同,一位一位比较大小 12 } 13 } 14 return 1; 15 } 16 void sub(int* a,int* b,string s,string t) //a-b,s对应a,t对应b 17 { 18 if(larger(s,t)) 19 { 20 for(int i = 1;i<=a[0];i++) 21 { 22 a[i] -= b[i]; 23 if(a[i]<0) 24 { 25 a[i+1]--;//借位 26 a[i] += 10; 27 } 28 } 29 a[0]++;//去除前导零 30 while(a[a[0]]==0&&a[0]>1) 31 { 32 a[0]--; 33 } 34 for(int i = a[0];i>0;i--) 35 { 36 cout << a[i]; 37 } 38 cout << endl; 39 } 40 else 41 { 42 for(int i = 1;i<=b[0];i++) 43 { 44 b[i] -= a[i]; 45 if(b[i]<0) 46 { 47 b[i+1]--;//借位 48 b[i]+=10; 49 } 50 } 51 b[0]++;//去除前导零 52 while(b[b[0]]==0&&b[0]>0) 53 { 54 b[0]--; 55 } 56 cout << "-"; 57 for(int i = b[0];i>0;i--) 58 { 59 cout << b[i]; 60 } 61 cout << endl; 62 } 63 }
高精度乘法:
注意了,因为模拟手算的过程,为了方便,这里用了零一个数组c来存乘法的结果,看一下c在运算过程中是怎么存储数到对应位置的。
1 2 3 3 2 1
* 2 3 2 3 0
------- ------------
3 6 9 6 4 2
24 6 9 6 3
(此为正常手算)因为是倒着存储的,数组c每次存进数的位置应该往后移
1 void mul(int* a,int* b) 2 { 3 memset(c,0,sizeof(c)); 4 for(int i = 1;i<=a[0];i++) 5 { 6 for(int j = 1;j<=b[0];j++) 7 { 8 c[i+j-1] = a[i]*b[j];//a中每一个数分别乘以b的每一个数后加到对应的c的位置上 9 c[i+j] = c[i+j-1]/10;//进位 10 c[i+j-1] %= 10;//余下来的数 11 } 12 } 13 c[0] = a[0]+b[0]+1;//c[0]中存放数字的位数 14 while(c[c[0]]==0&&c[0]>1)//去除前导零,同时让c正确统计c的数字的位数 15 { 16 c[0]--; 17 } 18 for(int i = c[0];i>0;i--) 19 { 20 cout << c[i]; 21 } 22 cout << endl; 23 }
高精度除法:
分为高精度除以低精度和高精度除以高精度
第一种:
直接用每一位加上上一项余数的10倍的和除以除数即可得最终结果,注意要去掉前导零。
1 void div1(int* a,long long b)//高精除以低精 2 { 3 int lena,lenc; 4 int x = 0;//x为前一次运算的余数 5 memset(c,0,sizeof(c)); 6 for(int i = a[0];i>0;i--)//注意顺序从第一位开始计算 7 { 8 c[i] = (10*x+a[i])/b;//这一位加上前一次计算的余数 9 x = (10*x+a[i])%b; 10 } 11 lenc = 1; 12 while(c[lenc]==0&&lenc<a[0])//出去前导零 13 { 14 lenc++; 15 } 16 for(int i = lenc;i<=a[0];i++) 17 { 18 cout << c[i]; 19 } 20 cout << endl; 21 }
第二种:
不再直接每一位除,要找到刚开始除的位置,在哪呢?(a[0]-b[0]+1)
比如1 2 3 4 5除以1 2 3 a[0]-b[0]+1=3
5 4 3 2 1
↑此为开始除的位置
还要注意不能直接除以除数,因为除数也是高精度,就用减法代模拟除法,细节见代码:
1 int cmp(int* a,int* b)//比较a是不是大于等于b 2 { 3 if(a[0]!=b[0]) 4 { 5 return a[0]>b[0]; 6 } 7 for(int i = a[0];i>0;i--) 8 { 9 if(a[i]!=b[i]) 10 { 11 return a[i]>b[i]; 12 } 13 } 14 return 1; 15 } 16 void sub(int* a,int *b)//用a减去b 17 { 18 for(int i = 1;i<=a[0];i++) 19 { 20 a[i]-=b[i]; 21 if(a[i]<0) 22 { 23 a[i]+=10; 24 a[i+1]--; 25 } 26 } 27 a[0]++; 28 while(a[0]>1&&a[a[0]]==0) 29 { 30 a[0]--; 31 } 32 return; 33 } 34 void div2(int* a,int* b)//高精除以高精 35 { 36 int temp[max_n]; 37 c[0] = a[0]-b[0]+1;//c[0]的位置为a比b多的数+1的地方 38 for(int i = c[0]; i>0; i--) 39 { 40 memset(temp,0,sizeof(temp));//temp存储被除数 41 for(int j = 1; j<=b[0]; j++) 42 { 43 temp[i+j-1] = b[j];//对应从i开始的地方,复制数组b到temp中 44 } 45 temp[0] = b[0]+i-1; 46 while(cmp(a,temp))//用减法模拟 47 { 48 /*cout << "a" << endl; 49 for(int i = 1;i<=a[0];i++) 50 { 51 cout << a[i]; 52 } 53 cout << endl;*/ 54 c[i]++; 55 sub(a,temp); 56 } 57 } 58 c[0]++; 59 while(c[0]>1&&c[c[0]]==0)//删除前导零 60 { 61 c[0]--; 62 } 63 cout << "商为:"; 64 for(int i = c[0]; i>0; i--) 65 { 66 cout << c[i]; 67 } 68 cout << endl; 69 cout << "余数为:"; 70 if(a[0]==0) 71 { 72 cout << 0 << endl; 73 } 74 else 75 { 76 for(int i = a[0]; i>0; i--) 77 { 78 cout << a[i]; 79 } 80 cout << endl; 81 } 82 }
以上就是高精度算法的大数运算,不失为一个好模板,只是相应的输出操作有可能会改变。
代码汇总:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string> 3 #include <memory.h> 4 #define max_n 250 5 using namespace std; 6 int a[max_n]; 7 int b[max_n]; 8 int c[max_n<<1]; 9 string s,t; 10 int len; 11 void add(int* a,int* b) 12 { 13 len = max(a[0],b[0]); 14 for(int i = 1;i<=len;i++) 15 { 16 a[i] = a[i]+b[i]; 17 a[i+1] += a[i]/10;//进位 18 a[i] %= 10; 19 } 20 len++;//去除前导零 21 while(a[len]==0&&len>1) 22 { 23 len--; 24 } 25 for(int i = len;i>0;i--) 26 { 27 cout << a[i]; 28 } 29 cout << endl; 30 } 31 int larger(string s,string t) //看s是否>=t 32 { 33 if(s.length()!=t.length()) 34 { 35 return s.length()>t.length();//长度不同长的大 36 } 37 for(int i = 0;i<s.length();i++) 38 { 39 if(s[i]!=t[i]) 40 { 41 return s[i]>t[i];//长度相同,一位一位比较大小 42 } 43 } 44 return 1; 45 } 46 void sub(int* a,int* b,string s,string t) //a-b,s对应a,t对应b 47 { 48 if(larger(s,t)) 49 { 50 for(int i = 1;i<=a[0];i++) 51 { 52 a[i] -= b[i]; 53 if(a[i]<0) 54 { 55 a[i+1]--;//借位 56 a[i] += 10; 57 } 58 } 59 a[0]++;//去除前导零 60 while(a[a[0]]==0&&a[0]>1) 61 { 62 a[0]--; 63 } 64 for(int i = a[0];i>0;i--) 65 { 66 cout << a[i]; 67 } 68 cout << endl; 69 } 70 else 71 { 72 for(int i = 1;i<=b[0];i++) 73 { 74 b[i] -= a[i]; 75 if(b[i]<0) 76 { 77 b[i+1]--;//借位 78 b[i]+=10; 79 } 80 } 81 b[0]++;//去除前导零 82 while(b[b[0]]==0&&b[0]>0) 83 { 84 b[0]--; 85 } 86 cout << "-"; 87 for(int i = b[0];i>0;i--) 88 { 89 cout << b[i]; 90 } 91 cout << endl; 92 } 93 } 94 void mul(int* a,int* b) 95 { 96 memset(c,0,sizeof(c)); 97 for(int i = 1;i<=a[0];i++) 98 { 99 for(int j = 1;j<=b[0];j++) 100 { 101 c[i+j-1] = a[i]*b[j];//a中每一个数分别乘以b的每一个数后加到对应的c的位置上 102 c[i+j] = c[i+j-1]/10;//进位 103 c[i+j-1] %= 10;//余下来的数 104 } 105 } 106 c[0] = a[0]+b[0]+1;//c[0]中存放数字的位数 107 while(c[c[0]]==0&&c[0]>1)//去除前导零,同时让c正确统计c的数字的位数 108 { 109 c[0]--; 110 } 111 for(int i = c[0];i>0;i--) 112 { 113 cout << c[i]; 114 } 115 cout << endl; 116 } 117 void div1(int* a,long long b)//高精除以低精 118 { 119 int lena,lenc; 120 int x = 0;//x为前一次运算的余数 121 memset(c,0,sizeof(c)); 122 for(int i = a[0];i>0;i--)//注意顺序从第一位开始计算 123 { 124 c[i] = (10*x+a[i])/b;//这一位加上前一次计算的余数 125 x = (10*x+a[i])%b; 126 } 127 lenc = 1; 128 while(c[lenc]==0&&lenc<a[0])//出去前导零 129 { 130 lenc++; 131 } 132 for(int i = lenc;i<=a[0];i++) 133 { 134 cout << c[i]; 135 } 136 cout << endl; 137 } 138 int cmp(int* a,int* b)//比较a是不是大于等于b 139 { 140 if(a[0]!=b[0]) 141 { 142 return a[0]>b[0]; 143 } 144 for(int i = a[0];i>0;i--) 145 { 146 if(a[i]!=b[i]) 147 { 148 return a[i]>b[i]; 149 } 150 } 151 return 1; 152 } 153 void sub(int* a,int *b)//用a减去b 154 { 155 for(int i = 1;i<=a[0];i++) 156 { 157 a[i]-=b[i]; 158 if(a[i]<0) 159 { 160 a[i]+=10; 161 a[i+1]--; 162 } 163 } 164 a[0]++; 165 while(a[0]>1&&a[a[0]]==0) 166 { 167 a[0]--; 168 } 169 return; 170 } 171 void div2(int* a,int* b)//高精除以高精 172 { 173 int temp[max_n]; 174 c[0] = a[0]-b[0]+1;//c[0]的位置为a比b多的数+1的地方 175 for(int i = c[0]; i>0; i--) 176 { 177 memset(temp,0,sizeof(temp));//temp存储被除数 178 for(int j = 1; j<=b[0]; j++) 179 { 180 temp[i+j-1] = b[j];//对应从i开始的地方,复制数组b到temp中 181 } 182 temp[0] = b[0]+i-1; 183 while(cmp(a,temp))//用减法模拟 184 { 185 /*cout << "a" << endl; 186 for(int i = 1;i<=a[0];i++) 187 { 188 cout << a[i]; 189 } 190 cout << endl;*/ 191 c[i]++; 192 sub(a,temp); 193 } 194 } 195 c[0]++; 196 while(c[0]>1&&c[c[0]]==0)//删除前导零 197 { 198 c[0]--; 199 } 200 cout << "商为:"; 201 for(int i = c[0]; i>0; i--) 202 { 203 cout << c[i]; 204 } 205 cout << endl; 206 cout << "余数为:"; 207 if(a[0]==0) 208 { 209 cout << 0 << endl; 210 } 211 else 212 { 213 for(int i = a[0]; i>0; i--) 214 { 215 cout << a[i]; 216 } 217 cout << endl; 218 } 219 } 220 int main() 221 { 222 memset(a,0,sizeof(a)); 223 memset(b,0,sizeof(b)); 224 cin >> s >> t;//输入两个大数到字符串中 225 a[0] = s.length();//存储字符串s元素的个数,即大数a的位数 226 for(int i = 1;i<=a[0];i++)//并转化为整数存储在数组a中的对应位置 227 { 228 a[i] = s[a[0]-i]-'0'; 229 } 230 b[0] = t.length();//存储字符串t的个数,即大数b的位数 231 for(int i = 1;i<=b[0];i++)//并转化为整数存储在数组b中的对应位置 232 { 233 b[i] = t[b[0]-i]-'0'; 234 } 235 return 0; 236 }
参考文章:
这里有讲得很清楚的高精度四则运算的博客:
老樊Lu码,高精度加、减、乘、除算法实现详解,https://blog.csdn.net/fanyun_01/article/details/79967170