高精度算法之大数运算

思想:

先用字符串来读入大整数,然后用数组来存储大整数。与上一篇的所讲思路不同的是,这次是数组的每一个元素对应大整数的一个数,从而模拟手算过程。

主要实现思路与手算无太大差别。主要是一些细节上。

统一做个说明:模拟大数的数组的第零个元素保存的是数字个数(不包括第零个元素),而且数组从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 }

以上就是高精度算法的大数运算,不失为一个好模板,只是相应的输出操作有可能会改变。

代码汇总:

  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 }
View Code

参考文章:

这里有讲得很清楚的高精度四则运算的博客:

老樊Lu码,高精度加、减、乘、除算法实现详解,https://blog.csdn.net/fanyun_01/article/details/79967170

猜你喜欢

转载自www.cnblogs.com/zhanhonhao/p/11255660.html