大数问题
大数是指计算的数值非常大或者对运算的精度要求非常高,用已知的数据类型无法精确表示的数值。
大数问题主要有以下四种:
==================================
1. 大数相加
2. 大数相乘
3. 大数阶乘
4. 大数幂乘
==================================
下面我们一起解决这四种问题。
Problem 1 大数相加
一般的int,long等类型无法精确表达数值。
我们就考虑以字符串的形式读入这两个数,利用vector来表示这两个数值,
代码:
1 string s1, s2; 2 cin>>s1>>s2; 3 int i; 4 vector<int> v1(s1.size()), v2(s2.size()); 5 for(i = 0; i < s1.size(); i++) 6 { 7 v1[i] = s1[i] - '0'; 8 } 9 for(i = 0; i < s2.size(); i++) 10 { 11 v2[i] = s2[i] - '0'; 12 }
利用vector的空间可以无限扩展,因此我们利用vector来模拟计算这两个数的相加。
根据加法规则我们可以知道,个位与个位相加,十位与十位相加...
代码:
1 vector<int> f(vector<int> v1, vector<int> v2) 2 {
#将两个数字的位置倒过来,个位数字放在最前面,例如:123,倒过来即为321 3 reverse(v1.begin(),v1.end()); 4 reverse(v2.begin(),v2.end()); 5 int maxsize = v1.size();
#比较两个数字的位数,找到最长的 6 if(v2.size() > maxsize) 7 { 8 maxsize = v2.size(); 9 } 10 vector<int> v3(maxsize);
#记录每一位计算的进位 11 int carry = 0; 12 int i; 13 for(int i = 0; i < maxsize; i++) 14 { 15 int t = carry; 16 if(i < v1.size()) 17 t = t + v1[i]; 18 if(i < v2.size()) 19 t = t + v2[i];
#当相同位置上的数字相加超过10时,应该向高位进位 20 carry = t / 10; 21 v3[i] = t % 10; 22 }
#若最高位相加之后,需要进位,那么我们需要扩展vector 23 if(carry > 0) 24 v3.push_back(carry);
#最后将vector倒置,可以得到最终的相加结果 25 reverse(v3.begin(),v3.end()); 26 return v3; 27 }
Problem 2 大数相乘
例如:
位置: 4 3 2 1 0
数值1: 4 3 2
数值2: * 4 5
------------------------------------
结果: 20 15 10
16 12 8
-----------------------------------
16 32 23 10
-----------------------------------
1 9 4 4 0
从上面的例子中我们可以看出位置i和位置j的结果放在i+j的位置,最后再依次进行进位操作。
代码:
这里要注意初始结果申请的空间,最后在输出的时候需要进行处理。
1 vector<int> m(vector<int> v1, vector<int> v2) 2 { 3 reverse(v1.begin(),v1.end()); 4 reverse(v2.begin(),v2.end()); 5 int maxsize = v1.size(); 6 if(v2.size() > maxsize) 7 maxsize = v2.size(); 8 maxsize *= 2; 9 vector<int> v3(maxsize, 0); 10 int carry = 0; 11 for(int i = 0; i < v1.size(); i++) 12 for(int j = 0; j < v2.size(); j++) 13 { 14 v3[i+j] += v1[i]*v2[j]; 15 } 16 for(int i = 0; i < v3.size(); i++) 17 { 18 if(v3[i] >= 10) 19 { 20 v3[i+1] += v3[i]/10; 21 v3[i] = v3[i] % 10; 22 } 23 } 24 reverse(v3.begin(),v3.end()); 25 26 return v3; 27 }
输出处理:因为开始申请的空间可能有部分没有用到,但是在倒置的时候最前面可能出现多个0,利用flag记录非0的起点。
代码:
int flag = 0; while(v4[flag] == 0) flag++; for(i = flag; i < v4.size(); i++) cout<<v4[i]; cout<<endl;
Problem 3大数阶乘
一般阶乘很快就会超过int的表达范围,因此同样采用上面大数相乘的思想来计算大数阶乘,这里需要注意的是开始输入的n不是一个大数,但是随着计算,结果会越来越大。
利用循环来计算大数阶乘。
代码:
1 vector<int> m(vector<int> v1, vector<int> v2) 2 { 3 reverse(v1.begin(),v1.end()); 4 reverse(v2.begin(),v2.end()); 5 int maxsize = v1.size(); 6 if(v2.size() > maxsize) 7 maxsize = v2.size(); 8 maxsize *= 2; 9 vector<int> v3(maxsize, 0); 10 int carry = 0; 11 for(int i = 0; i < v1.size(); i++) 12 for(int j = 0; j < v2.size(); j++) 13 { 14 v3[i+j] += v1[i]*v2[j]; 15 } 16 for(int i = 0; i < v3.size(); i++) 17 { 18 if(v3[i] >= 10) 19 { 20 v3[i+1] += v3[i]/10; 21 v3[i] = v3[i] % 10; 22 } 23 } 24 reverse(v3.begin(),v3.end()); 25 26 return v3; 27 } 28 29 vector<int> intTovector(int x) 30 { 31 vector<int> v; 32 while (x) 33 { 34 v.push_back(x%10); 35 x /= 10; 36 } 37 reverse(v.begin(),v.end()); 38 return v; 39 } 40 41 vector<int> pre(vector<int> v) 42 { 43 vector<int> v1; 44 int flag = 0; 45 while(v[flag] == 0) 46 flag++; 47 for(int i = flag; i < v.size(); i++) 48 v1.push_back(v[i]); 49 return v1; 50 } 51 52 void p(vector<int> v) 53 { 54 for(int j = 0; j < v.size(); j++) 55 cout<<v[j]; 56 cout << endl; 57 } 58 59 vector<int> jiecheng(int n) 60 { 61 vector<int> v1(1,1); 62 if(n == 1) 63 return v1; 64 vector<int> v2(1,2); 65 if(n == 2) 66 return v2; 67 vector<int> v3 = v2; 68 for(int i = 3; i <= n; i++) 69 { 70 vector<int> t1 = intTovector(i); 71 p(t1); 72 vector<int> t2 = v3; 73 p(t2); 74 v3 = pre(m(t1,t2)); 75 p(v3); 76 cout << "===============" <<endl; 77 } 78 return v3; 79 }
Problem 4大数幂乘
一般阶乘很快就会超过int的表达范围,因此同样采用上面大数相乘的思想来循环计算大数阶乘。
代码:
1 vector<int> micheng(int n, int s) 2 { 3 vector<int> v = intTovector(n); 4 for(int i = 1; i < s; i++) 5 { 6 v = pre(m(v,intTovector(n))); 7 8 } 9 return v; 10 }