高精度算法之大數運算

思想:

先用字符串來讀入大整數,而後用數組來存儲大整數。與上一篇的所講思路不一樣的是,此次是數組的每個元素對應大整數的一個數,從而模擬手算過程。ios

主要實現思路與手算無太大差異。主要是一些細節上。c++

統一作個說明:模擬大數的數組的第零個元素保存的是數字個數(不包括第零個元素),並且數組從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 }

高精度減法:

減法的特別之處在於兩個數的大小不肯定,那咱們就先比較兩個數的大小,保證用大的數減去小的數,結果分類看是否加負號。ide

 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在運算過程當中是怎麼存儲數到對應位置的。spa

  1 2 3                                 3 2 1.net

  * 2 3                                 2 3 0code

  -------                               ------------blog

  3 6 9                                 6 4 2ci

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

相關文章
相關標籤/搜索