【演算法】大整數乘法
阿新 • • 發佈:2018-11-26
大整數乘法
問題描述
求兩個不超過200位的非負整數的積。
輸入形式
有兩行,每行是一個不超過200位的非負整數,沒有多餘的前導0。
輸出形式
一行,即相乘後的結果。結果裡不能有多餘的前導0,即如果結果是342,那麼就不能輸出為0342。
樣例輸入
1234567890
9876543210
樣例輸出
12193263111263526900
解題思路:
1 :採用了陣列的形式進行計算。將輸入的值以字元的形式存到陣列中取,再轉化成整數形式相乘。
2. 根據課本的描述採用分治的方法求解。主要部分是遞迴的不同種情況。當n=2時直接求解,當n>2,則對其進行分治。按照公式:A*B=a1*b1*10^n+[(a1+a0)*(b0+b1)-a1*a0-b1*b0]*10^n/2+a0*b0求解
#include<iostream> #include<cstring> using namespace std; int main(){ char A[200],B[200]; int X[200],Y[200]; int Z[401]={0}; cin>>A; cin>>B; int lenA = strlen(A); int lenB = strlen(B); int i,j; for(i=lenA-1,j=0;i>=0;i--) { X[j]=A[i]-'0'; j++; } for(i=lenB-1,j=0;i>=0;i--) { Y[j]=B[i]-'0'; j++; } for(i=0;i<lenA;i++) { for(j=0;j<lenB;j++) Z[i+j]=Z[i+j]+X[i]*Y[j]; } for(i=0;i<400;i++) { if(Z[i]>=10) { Z[i+1]=Z[i+1]+Z[i]/10; Z[i]=Z[i]%10; } } for(i=400;i>0;i--) { if(Z[i]==0) continue; else break; } for(;i>=0;i--) cout<<Z[i]; return 0; }
第二種:
#include<iostream> #include<string> #include<algorithm> #include<sstream> using namespace std; //string轉換為int int str_to_int(string s) { int num; stringstream ss(s); ss >> num; return num; } //int轉換為string string int_to_str(int num) { string s; stringstream ss; ss << num; ss >> s; return s; } //前置0 ,因為大數的長度必須要為2^n的倍數,才能劃分 //去掉前置零,substr()複製子字串 void removePrezero(string &s) { int i = 0; while (i < s.length() && s[i] == '0') //過濾前置零 i++; if (i < s.length()) s = s.substr(i); //複製剩餘子字串 else s = "0"; } //大數相加 string add(string s1, string s2) { string s = ""; //去掉前置0 removePrezero(s1); removePrezero(s2); //先把字串顛倒,方便相加 reverse(s1.begin(), s1.end()); reverse(s2.begin(), s2.end()); int c = 0; //記錄進位值 for (int i = 0;c|| i < max(s1.length(), s2.length()); i++) { int t = c; if (i < s1.length()) t += s1[i] - '0'; if (i < s2.length()) t += s2[i] - '0'; int d = t % 10; s = char(d + '0') + s; c = t / 10; } return s; } //大數相減 string sub(string &s1, string &s2) { string s = ""; string flag; //去掉前置0 removePrezero(s1); removePrezero(s2); //求長比較,確定正負 int len1 = s1.length(); int len2 = s2.length(); int len = len1>len2 ? len1 : len2; if (len1 < len2)flag = "-"; else if (len1 > len2)flag = "+"; else { //s.at(n) 返回s中下標為n的元素 int i; for (i = 0; i < len1; i++) { if (s1.at(i) > s2.at(i)) { flag = "+"; break; } else if (s1.at(i) < s2.at(i)) { flag = "-"; break; } } if (i == len1)s == "0"; } int* num = (int*)malloc(sizeof(int)*len); reverse(s1.begin(), s1.end()); reverse(s2.begin(), s2.end()); int c = 0; //記錄結果位數 for (int i = 0; i < len; i++) { int n1 = i < len1 ? s1[i] - '0' : 0; int n2 = i < len2 ? s2[i] - '0' : 0; if (flag == "+") num[c++] = n1 - n2; else num[c++] = n2 - n1; } for (int j = 0; j < c; j++) { if (num[j] < 0) { num[j] += 10; num[j + 1] -= 1; } } c--; //去除可能存在的前置零 while (num[c] == 0)c--; for (int j = 0; j <=c; j++){ s = char(num[j] + '0') + s ; } if (flag == "-")return flag + s; else return s; } //增加前置0 void addPrezero(string &s, int L) { for (int i = 0; i < L; i++) s = s.insert(0, "0"); } //增加後置0,大數*10^n 相當於在數的後面加n個0 string addLastzero(string s, int L) { string s1 = s; for (int i = 0; i < L; i++) s1 += "0"; return s1; } //大數相乘 string mult(string &s1, string &s2) { bool flag1 = false, flag2 = false; string sign; //記錄結果正負 if (s1.at(0) == '-') { flag1 = true; s1 = s1.substr(1); } if (s2.at(0) == '-') { flag2 = true; s2 = s2.substr(1); } if (flag1 || flag2) sign = "-"; else sign = "+"; int L = 4; //前置若干個0,使長度為2^n的倍數 if (s1.length() > 2 || s2.length() > 2) { if (s1.length() >= s2.length()) { while (L < s1.length()) L *= 2; if (L != s1.length()) addPrezero(s1, L - s1.length()); addPrezero(s2, L - s2.length()); } else { while (L < s2.length())L*=2; if (L != s2.length()) addPrezero(s2, L - s2.length()); addPrezero(s1, L - s1.length()); } } if (s1.length() == 1)addPrezero(s1, 1); if (s2.length() == 1)addPrezero(s2, 1); //進行運算 int n = s1.length(); string result, a0, a1, b0, b1; if (n > 1) { //大於1取n/2 a1 = s1.substr(0, n / 2); a0 = s1.substr(n / 2, n); b1 = s2.substr(0, n / 2); b0 = s2.substr(n / 2, n); } if (n == 2) { //n==2 計算 int x1 = str_to_int(a1); int x2 = str_to_int(a0); int y1 = str_to_int(b1); int y2 = str_to_int(b0); int num = (x1 * 10 + x2)*(y1 * 10 + y2); result = int_to_str(num); }else { // n!=2 採用公式求解 //A*B=a1*b1*10^n+[(a1+a0)*(b0+b1)-a1*a0-b1*b0]*10^n/2+a0*b0 string c2 = mult(a1, b1); string c0 = mult(a0, b0); string temp1 = add(a0, a1); string temp2 = add(b1, b0); string temp3 = add(c2, c0); string temp_c1 = mult(temp1, temp2); string c1 = sub(temp_c1, temp3); string s1 = addLastzero(c1, n / 2); string s2 =addLastzero(c2, n); result = add(add(s1, s2), c0); } if (sign == "-")result.insert(0, sign); return result; } int main() { string s1 ,s2; cin>>s1>>s2; cout << mult(s1, s2); }