大数乘法

分治算法首先讲了一个经典的乘法运算

具体的代码如下:  该算法的核心是计算xy=(10^n/2xl+xr)(10^n/2yl+yr)=10^nxlyl+10^n/2(xlyr+xryl)+xryr

 1 /************************************************************************/
 2 //函数功能:分治法求两个位数为N的整数的乘积
 3 //输入参数:X,Y分别为两个位数为N的整数
 4 //算法思想:分治算法,xy=(10n/2xl+xr)(10n/2yl+yr)=10nxlyl+10n/2(xlyr+xryl)+xryr
 5 //时间复杂度为:T(n)=O(nlog3)=O(n1.59)
 6 /************************************************************************/
 7 #include <iostream>
 8 #include <cmath>
 9 using namespace std;
10 #define SIGN(A) ((A > 0) ? 1 : -1)
11 
12 int IntegerMultiply(int X, int Y, int N)
13 {
14     int sign = SIGN(X) * SIGN(Y);   //确定结果的符号 
15     int x = abs(X);                 //取绝对值,去掉x,y符号 
16     int y = abs(Y);
17     if((0 == x) || (0 == y))
18         return 0;
19     if (1 == N)
20         return x*y;
21     else
22     {
23         int XL = x / (int)pow(10., (int)N/2); 
24         int XR = x - XL * (int)pow(10., N/2);
25         int YL = y / (int)pow(10., (int)N/2);
26         int YR = y - YL * (int)pow(10., N/2);
27         
28         int XLYL = IntegerMultiply(XL, YL, N/2);
29         int XRYR = IntegerMultiply(XR, YR, N/2);
30         int XLYRXRYL = IntegerMultiply(XL - XR, YR - YL, N/2) + XLYL + XRYR;
31         return sign * (XLYL * (int)pow(10., N) + XLYRXRYL * (int)pow(10., N/2) + XRYR);
32     }
33 }
34 
35 int main()
36 {
37     int x = 1234;
38     int y = 4321;
39     cout<<"x * y = "<<IntegerMultiply(x, y, 4)<<endl;
40     cout<<"x * y = "<<x*y<<endl;
41     return 0;
42 }

另外搜索到了一个很不错的大数程序,这里先mark一下:

  1 //设计一个支持大数运算的计算器,其中乘法使用分治法求解。该计算器支持加减乘除还有开方根运算。
  2 #include <iostream>
  3 #include <list>
  4 #include <string>
  5 #include <cstdio>
  6 #include <cctype>
  7 #include <cmath>
  8 using namespace std;
  9 list<char> Add(list<char> s, list<char> t);
 10 list<char> Sub(list<char> s, list<char> t);
 11 list<char> Mul(list<char> s, list<char> t);
 12 void Div(list<char> s, list<char> t);
 13 void  Root(list<char>);
 14 void print(list<char> ans);
 15 void printhelp()             //打印帮助信息
 16 {
 17     cout << "请选择要进行的大数运算" << endl;
 18     cout << "1:加法运算" << endl;
 19     cout << "2:减法运算" << endl;
 20     cout << "3:乘法运算" << endl;
 21     cout << "4:除法运算" << endl;
 22     cout << "5:开平方根运算" << endl;
 23     cout << "6:退出" << endl;
 24 }
 25 list<char> Add(list<char> num1,list<char> num2)  //加法运算
 26 {
 27     list<char> ans;
 28     list<char>::iterator iter1,iter2;
 29     iter1 = num1.begin();
 30     iter2 = num2.begin();
 31     int sign = 0;                                   //标记结果符号
 32     if((*iter1) == '-' && (*iter2) == '-')        //如果两个数都是负数
 33     {
 34         num1.pop_front();
 35         num2.pop_front();
 36         sign = 1;
 37         ans = Add(num1,num2);
 38         ans.push_front('-');
 39     }
 40     else if((*iter1) == '-' && (*iter2) != '-')      //如果一负一正
 41     {
 42         num1.pop_front();
 43         ans = Sub(num2,num1);
 44         
 45     }
 46     else if((*iter1) != '-' && (*iter2) == '-')      //如果一正一负
 47     {
 48         num2.pop_front();
 49         ans = Sub(num1,num2);
 50     }
 51     else                                          //如果都为正
 52     {
 53         int len1,len2,i,len,carry;
 54         len1 = num1.size();
 55         len2 = num2.size();
 56         if(len1 >= len2)                     //补齐两个数的位数
 57         {
 58             len = len1;
 59             for(i = 0; i < len1 - len2; i++)
 60                 num2.push_front('0');
 61         }
 62         else
 63         {
 64             len = len2;
 65             for(i = 0; i < len2 - len1; i++)
 66                 num1.push_front('0');
 67         }
 68         //print(num1);
 69         //print(num2);
 70         carry = 0;
 71         iter1 = num1.end();
 72         iter2 = num2.end();
 73         iter1--;
 74         iter2--;
 75         for(;(iter1 != num1.begin()) && (iter2 != num2.begin()); --iter1,--iter2)  //进行运算
 76         {
 77             i = (*iter1 - '0') + (*iter2 - '0') + carry;
 78             //cout << (*iter1 - '0') << " " << (*iter2 - '0') << " " << i << endl;
 79             ans.push_front((i % 10) + '0');
 80             carry = i / 10;
 81         }
 82         i = (*iter1 - '0') + (*iter2 - '0') + carry;
 83         //cout << (*iter1 - '0') << " " << (*iter2 - '0') << " " << i << endl;
 84         ans.push_front((i % 10) + '0');
 85         carry = i / 10;
 86         if(carry)
 87             ans.push_front(carry+'0');
 88     }
 89     return ans;                                                     //返回结果
 90 }
 91 list<char> Sub(list<char> num1,list<char> num2)                    //减法运算
 92 {
 93     list<char> ans;
 94     int sign = 0;
 95     list<char>::iterator iter1,iter2;
 96     int len1,len2,len;
 97     iter1 = num1.begin();
 98     iter2 = num2.begin();
 99     if((*iter1) == '-' && (*iter2) == '-')                  //如果两个数都为负数
100     {
101         num2.pop_front();
102         num1.pop_front();
103         ans = Sub(num2,num1);
104         //ans.push_front('-');
105     }
106     else if( (*iter1) == '-' && (*iter2) != '-')              //如果一负一正
107     {
108         num1.pop_front();
109         ans = Add(num1,num2);
110         ans.push_front('-');
111     }
112     else if( (*iter1) != '-' && (*iter2) == '-')              //如果一正一负
113     {
114         num2.pop_front();
115         ans = Add(num1,num2);
116         
117     }
118     else                                                   //如果都为正
119     {
120         len1 = num1.size();
121         len2 = num2.size();
122         if(len1 >= len2)                                 //补齐位数
123         {
124             len = len1;
125             for(int i = 0; i < len1 - len2; i++)
126                 num2.push_front('0');
127         }
128         else
129         {
130             len = len2;
131             for(int i = 0; i < len2 - len1; i++)
132                 num1.push_front('0');
133         }
134         //print(num1);cout << endl;
135         //print(num2);cout << endl;
136         int carry = 0,i;
137         iter1 = num1.end();
138         iter2 = num2.end();
139         iter1--;
140         iter2--;
141         for(;(iter1 != num1.begin()) && (iter2 != num2.begin()); --iter1,--iter2)    //进行运算
142         {
143             i = (*iter1 - '0' - carry) - (*iter2 - '0');
144             carry = 0;
145             if( i < 0)
146             {
147                 i += 10;
148                 carry = 1;
149             }
150             //cout << (*iter1 - '0') << " " << (*iter2 - '0') << " " << i << endl;
151             ans.push_front((i % 10) + '0');
152         }
153         i = (*iter1 - '0' - carry) - (*iter2 - '0');
154         if(i < 0)
155         {
156             i += 10;
157             sign = 1;
158         }
159         //cout << (*iter1 - '0') << " " << (*iter2 - '0') << " " << i << endl;
160         if(i) ans.push_front(i + '0');
161         if(sign)
162             ans.push_front('-');
163     }
164     return ans;
165 }
166 list<char> Mul(list<char> num1,list<char> num2)  // 分治法求两大数的积
167 {
168     list<char> ans;
169     int sign = 0;
170     int len1,len2,len;
171     list<char>::iterator iter1,iter2,iter;
172     list<char> high,low;
173     list<char> anshigh,anslow;
174     int th,tl;
175     int i,j,k;
176     //print(num1);cout << endl;
177     //print(num2);cout << endl;
178     if(num1.size() == 1 && num2.size() == 1)     //如果两数都已是一位数,则进行运算
179     {
180         th = *(num1.begin()) - '0';
181         tl = *(num2.begin()) - '0';
182         th *= tl;
183         ans.push_front( th % 10 + '0');
184         ans.push_front( th / 10 + '0');
185         return ans;
186     }
187     else if(num1.size() == 1 && num2.size() > 1)            //如果num1位数大于1,则对Num1分治求积
188     {
189          if(*(num2.begin()) == '-')
190            {
191                 sign = 1;
192                 num2.pop_front();
193            }
194          len2 = num2.size();
195          if(len2 == 1)
196          {
197             ans = Mul(num1,num2);
198             if(sign)
199                 ans.push_front('-');
200          }
201          else
202          {
203             for(iter= num2.begin(),i = 0; i < len2 / 2; i++,iter++)
204             {
205                 high.push_back(*iter);
206             }
207             for(;iter!=num2.end();iter++)
208             {
209                 low.push_back(*iter);
210             }
211             len = low.size();
212             anshigh = Mul(num1,high);                 //num1分为两部分,high,low
213             anslow = Mul(num1,low);
214             for(i = 0; i < len; i++)
215                 anshigh.push_back('0');
216             ans = Add(anshigh,anslow);                 //合并结果
217             if(sign)
218                 ans.push_front('-');
219          }
220          return ans;
221     }
222     else if(num2.size() == 1 && num1.size() > 1)              //如果num2位数大于1,则对Num2分治求积
223     {
224          if(*(num1.begin()) == '-')
225            {
226                 sign = 1;
227                 num1.pop_front();
228            }
229          len1 = num1.size();
230          if(len2 == 1)
231          {
232             ans = Mul(num1,num2);
233             if(sign)
234                 ans.push_front('-');
235          }
236          else
237          {
238             for(iter= num1.begin(),i = 0; i < len1 / 2; i++,iter++)
239             {
240                 high.push_back(*iter);
241             }
242             for(;iter!=num1.end();iter++)
243             {
244                 low.push_back(*iter);
245             }
246             len = low.size();
247             anshigh = Mul(num2,high);                   //num2分为两部分,high,low
248             anslow = Mul(num2,low);
249             for(i = 0; i < len; i++)
250                 anshigh.push_back('0');
251             ans = Add(anshigh,anslow);                    //合并结果
252             if(sign)
253                 ans.push_front('-');
254          }
255          return ans;
256     }                                                       //如果两数位数都大于1,则都运用分治
257     else
258     {
259         list<char> num1high,num1low,num2high,num2low;
260         int flag1 = 0,flag2 = 0;
261         if(*(num1.begin()) == '-')
262         {
263             flag1 = 1;
264             num1.pop_front();
265         }
266         if(*(num2.begin()) == '-')
267         {
268             flag2 = 1;
269             num2.pop_front();
270         }
271         if((flag1 == 1 && flag2 == 0)||(flag1 == 0 && flag2 == 1))  //如果有一正一负,则标记结果为负
272         {
273             sign = 1;
274         }
275         len1 = num1.size();
276         len2 = num2.size();
277         if(len1 == 1 || len2 == 1)                 //如果有一个数是一位数,则直接递归调用
278         {
279             ans = Mul(num1,num2);
280             if(sign)
281                 ans.push_front('-');
282         }
283         else
284         {                                                //否则分治法求
285             for(iter = num1.begin(),i = 0; i < len1 / 2; iter++,i++)
286                 num1high.push_back(*iter);            //被乘数高位部分
287             for( ; iter != num1.end(); iter++)
288                 num1low.push_back(*iter);                 //被乘数低位部分
289             for(iter = num2.begin(),i = 0; i < len2 / 2; iter++,i++)
290                 num2high.push_back(*iter);                  //乘数高位部分
291             for( ; iter != num2.end(); iter++)
292                 num2low.push_back(*iter);                    //乘数低位部分
293             int a = (len1 + 1) / 2;
294             int b = (len2 + 1) / 2;
295             list<char> AC,AD,BC,BD;
296             //print(num2high);cout << endl;
297             //print(num2low);cout << endl;
298             AC = Mul(num1high,num2high);                  //运用X=A*10^a + B; Y= C*10^b + D;
299             AD = Mul(num1high,num2low);                   // X*Y = AC * 10 ^(a+b) + AD *10^a + BC * 10 ^b + BD公式求
300             BC = Mul(num1low,num2high);
301             BD = Mul(num1low,num2low);
302             for(i = 0; i < a + b; i++)
303                 AC.push_back('0');
304             for(i = 0; i < a; i++)
305                 AD.push_back('0');
306             for(i = 0; i < b; i++)
307                 BC.push_back('0');
308             ans = Add(AC,AD);
309             ans = Add(ans,BC);
310             ans = Add(ans,BD);                            //累加结果
311             if(sign)
312                 ans.push_front('-');
313         }
314         return ans;
315     }
316 }
317 void Div(list<char> num1,list<char> num2)                 //用辗转相除求结果
318 {
319     list<char> ans;
320     list<char> temp;
321     int len1,len2,len;
322     int i,j,k;
323     int sign = 0;
324     int flag1 = 0,flag2 = 0;
325     list<char>::iterator iter;
326     if(*(num1.begin()) == '-')
327     {
328         flag1 = 1;
329         num1.pop_front();
330     }
331     if(*(num2.begin()) == '-')
332     {
333         flag2 = 1;
334         num2.pop_front();
335     }
336     if((flag1 == 1 && flag2 != 1) || (flag1 == 0 && flag2 == 1))
337         sign = 1;                                          //标记结果符号
338     len1 = num1.size();
339     len2 = num2.size();
340     if(len1 < len2)                                 //如果被除数小于除法,除数为0
341     {
342         cout << "商是0;余数是" ;
343         print(num2);
344         cout << endl;
345         return ;
346     }
347     else                                               //用辗转相除求结果
348     {
349         for(iter = num1.begin(),i = 0; i < len2 ;++i,++iter)
350             temp.push_back(*iter);
351         list<char> digit,res;
352         for(j = 0; j < 10; j++)
353         {
354                 digit.clear();
355                 digit.push_back(j + '0');
356                 res = Mul(num2,digit);
357                 res = Sub(temp,res);
358                 if(*(res.begin()) == '-')
359                     break;
360         }
361             //cout << endl;print(temp); cout << endl;
362         j -= 1;
363         if(j > 0)
364         {
365             digit.clear();
366             digit.push_back(j + '0');
367             temp = Sub(temp,num2);
368             ans.push_back(j + '0');
369         }
370         
371         for(;iter != num1.end();++iter)
372         {
373             temp.push_back(*iter);
374             for(j = 0; j < 10; j++)
375             {
376                 digit.clear();
377                 digit.push_back(j + '0');
378                 res = Mul(num2,digit);
379                 res = Sub(temp,res);
380                 if(*(res.begin()) == '-')
381                     break;
382             }
383             //cout << endl;print(temp); cout << endl;
384             j -= 1;
385             digit.clear();
386             digit.push_back(j + '0');
387             res = Mul(num2,digit);
388             temp = Sub(temp,res);
389             ans.push_back(j + '0');
390         }
391         if(sign)
392             ans.push_front('-');
393     }
394     cout << "商是";
395     print(ans);
396     cout << ";余数是" ;
397     print(temp);
398     cout << endl;
399     return ;
400 }
401 void  Root(list<char> num1)                     //求大数的平方根,用枚举算法暴力搜索算法求
402 {
403     list<char> ans;
404     int len1;
405     list<char> digit,temp;
406     len1 = num1.size();
407     int a = len1 / 2;                            //a是结果的最少位数
408     int i;
409     digit.push_back('1');
410     ans.push_back('1');                        //从ans=10 ^ a 开始搜索
411     for(i = 0; i < a - 1; i++)
412         ans.push_back('0');
413     while(true)                                  //搜到则结束
414     {
415         temp = Mul(ans,ans);
416         temp = Sub(num1,temp);
417         if(*(temp.begin()) == '-')                      //如果当前ans的平方大于num1,则得结果
418             break;
419         ans = Add(ans,digit);
420     }
421     ans = Sub(ans,digit);
422     print(ans);
423     cout << endl;
424 }
425 list<char> translate(string input)
426 {
427     list<char> res;
428     int len = input.length();
429     for(int i = 0; i < len; i++)
430         res.push_back(input[i]);
431     return res;
432 }
433 void print(list<char> ans)
434 {
435     list<char>::iterator iter;
436     int flag = 1;
437     iter = ans.begin();
438     if(*iter == '-')
439      {
440         cout << *iter;
441         iter++;
442      }
443     for(;iter != ans.end(); ++iter)
444     {
445         if(*iter == '0' && flag)
446             continue;
447             //cout << (*iter);
448         else
449         {
450             flag = 0;
451             cout << (*iter);
452         }
453     }
454     if( flag == 1)
455         cout << 0 ;;
456     //cout << endl;
457 }
458 int main()
459 {
460     char choice;         //选择要进行的运算
461     list<char> num1;
462     list<char> num2;
463     list<char> res;
464     string input;
465     while(true)
466     {
467         cout << endl;
468         printhelp();
469         cin >> choice;
470         switch(choice)
471         {
472             case '1':                      //如果选择加法运算
473                 cout << "请输入第一个数" << endl;
474                 cin >> input;
475                 num1 = translate(input);
476                 cout << "请输入第二个数" << endl;
477                 cin >> input;
478                 num2 = translate(input);
479                 res = Add(num1,num2);
480                 print(num1);
481                 cout << " + " ;
482                 print(num2);
483                 cout << " = ";
484                 print(res);
485                 cout << endl;
486                 break;
487             case '2':                    //选择减法运算
488                 cout << "请输入第一个数" << endl;
489                 cin >> input;
490                 num1 = translate(input);
491                 cout << "请输入第二个数" << endl;
492                 cin >> input;
493                 num2 = translate(input);
494                 res = Sub(num1,num2);
495                 print(num1);
496                 cout <<" - " ;
497                 print(num2);
498                 cout << " = ";
499                 print(res);
500                 cout << endl;
501                 break;
502             case '3':                  //选择乘法运算
503                 cout << "请输入第一个数" << endl;
504                 cin >> input;
505                 num1 = translate(input);
506                 cout << "请输入第二个数" << endl;
507                 cin >> input;
508                 num2 = translate(input);
509                 res = Mul(num1,num2);
510                 print(num1);
511                 cout <<" * " ;
512                 print(num2);
513                 cout << " = ";
514                 print(res);
515                 cout << endl;
516                 break;
517             case '4':                      //选择除法运算
518                 cout << "请输入第一个数" << endl;
519                 cin >> input;
520                 num1 = translate(input);
521                 cout << "请输入第二个数" << endl;
522                 cin >> input;
523                 num2 = translate(input);
524                 print(num1);
525                 cout << " / " ;
526                 print(num2);
527                 cout << " = ";
528                 if(num2.size() == 1 && (*(num2.begin()) == '0'))
529                 {
530                     cout << "divided zero error" << endl;
531                     break;
532                 }
533                 Div(num1,num2);
534                 //print(res);
535                 cout << endl;
536                 break;
537             case '5':                         //选择求根运算
538                 cout << "请输入第一个数" << endl;
539                 cin >> input;
540                 num1 = translate(input);
541                 if(*(num1.begin()) == '-')
542                 {
543                     cout << "负数没有实数平方根" << endl;
544                     break;
545                 }
546                 Root(num1);
547                 break;
548             case '6':
549                 return 0;
550             default:
551                   break;
552         }
553     }
554 }
View Code
原文地址:https://www.cnblogs.com/liugl7/p/4925467.html